Create a Melee Combat System in Unity and C# | Fantacode Studios | Skillshare
Search

Playback Speed


1.0x


  • 0.5x
  • 0.75x
  • 1x (Normal)
  • 1.25x
  • 1.5x
  • 1.75x
  • 2x

Create a Melee Combat System in Unity and C#

teacher avatar Fantacode Studios

Watch this class and thousands more

Get unlimited access to every class
Taught by industry leaders & working professionals
Topics include illustration, design, photography, and more

Watch this class and thousands more

Get unlimited access to every class
Taught by industry leaders & working professionals
Topics include illustration, design, photography, and more

Lessons in This Class

    • 1.

      Introduction

      3:58

    • 2.

      Section Intro

      1:14

    • 3.

      Project Setup

      4:00

    • 4.

      Camera Controller

      22:53

    • 5.

      Character Movement

      20:48

    • 6.

      Animation Setup

      17:02

    • 7.

      Adding Animations to Character

      15:35

    • 8.

      Collisions and Gravity

      25:02

    • 9.

      Controller Input

      5:38

    • 10.

      Performing Attack

      30:13

    • 11.

      Reacting to Attacks

      29:18

    • 12.

      Attack States

      13:36

    • 13.

      Combos & Architecting Attacks as Scriptable Objects

      25:25

    • 14.

      Different Attack Hitboxes

      15:12

    • 15.

      Enemy AI

      25:49

    • 16.

      Chasing the Player

      22:54

    • 17.

      Combat Movement

      18:40

    • 18.

      Combat Movement || - Circling around the Player

      21:03

    • 19.

      Improving Circling

      34:17

    • 20.

      Attacking the Player One by One

      42:21

    • 21.

      Retreating after Attack

      15:13

    • 22.

      Performing Combos

      5:15

    • 23.

      Counter Attacks

      40:01

    • 24.

      Targeting System

      30:09

    • 25.

      Lock On Combat Mode

      33:17

    • 26.

      Directional Attacks & Rotating while attacking

      16:33

    • 27.

      Controller Input Setup for Combat

      10:06

    • 28.

      Stunned After Taking Hit

      21:56

    • 29.

      Long Range Attacks

      22:52

    • 30.

      Moving To Target Improvements

      13:10

    • 31.

      Combat Improvements & Edge Case Fixes

      21:32

    • 32.

      Health, Taking Damages & Dying

      16:15

    • 33.

      Alerting nearby enemies when a target is spotted

      12:50

  • --
  • Beginner level
  • Intermediate level
  • Advanced level
  • All levels

Community Generated

The level is determined by a majority opinion of students who have reviewed this class. The teacher's recommendation is shown until at least 5 student responses are collected.

38

Students

--

Project

About This Class

In this course, you’ll learn to create a third-person melee combat system in Unity with features like combos, counterattacks, intelligent enemy AI, etc. We'll design this system in a modular, data-driven, and scalable way using clean coding practices. So in this course, you’ll not only learn to build this system, but you’ll also learn lots of valuable game programming concepts that you can use throughout your career

So the combat system that we’re going to create will be a free-flow combat system. That means enemies won’t attack the player mindlessly; instead, they’ll attack in a coordinated way by circling the player and attacking one at a time. This is the type of combat used in modern-day games like Assassin's Creed, Batman Arkham series, Marvel’s Spider-Man, etc. This combat system will also be easily customizable, so if you want to use punch and kick attacks instead of sword attacks, you can do that easily without changing a single line of code

So we’ll be building all this step-by-step from scratch. We’ll start by making a basic third-person controller. We’ll not use any assets for it; we’ll build it from scratch because it’s a good way to learn the fundamentals of gameplay programming. And then we'll give our character the ability to attack. We’ll architect the attacks using scriptable objects in Unity so that the designer will be able to create and edit different attack combos without changing the code. Then we'll start building the enemy AI. We'll be architecting the enemy AI using a finite-state machine. It's a technique that’s been used for building AI in games for the last 25 years. It's used in popular games like Last of Us, the Batman Arkham series, and many more. So we'll build a Finite-State Machine from scratch and create our enemies using it. We'll start by creating simple enemy behaviors like Idling and Chasing the player, then we'll implement more advanced behaviors like circling the player and attacking him in a coordinated way. Once we're done with the Enemy AI, we'll implement the counterattacks.

Throughout this course, you’ll learn lots of game programming skills. You’ll learn lots of intermediate-level C# concepts like Generic Classes, Dictionary, LINQ, Inheritance, etc. You’ll also learn to use Mathematical concepts like Trigonometry, Dot Product, Cross Product, etc. So the skills and techniques that you learn from this course will be really helpful for you if want to pursue a career as a game programmer.

Meet Your Teacher

Level: Intermediate

Class Ratings

Expectations Met?
    Exceeded!
  • 0%
  • Yes
  • 0%
  • Somewhat
  • 0%
  • Not really
  • 0%

Why Join Skillshare?

Take award-winning Skillshare Original Classes

Each class has short lessons, hands-on projects

Your membership supports Skillshare teachers

Learn From Anywhere

Take classes on the go with the Skillshare app. Stream or download to watch on the plane, the subway, or wherever you learn best.

Transcripts

1. Introduction: Hey phone. In this course you'll learn how to create a third person male combat system, Unity with features like combos, counterattacks, intelligent enemy AI, and all that. We'll design the system in a modular, data driven, and scalable way using cleaning practices. You'll not really learn how to build the system in this course, but you'll also learn lots of valuable game programming concepts that you can use throughout your career. The combat system that you're going to create will be a free flow combat system. That means the enemy won't attack the player mindlessly. Instead, they'll attack in a coordinated way by circling around the player and attacking one at a time. This is the type of combat system used in most of the modern diggings like assassin screed, Batman, Narcosis, Marvel, Spider Man, et cetera. The combat system that build will also be easily customizable. If you want to use Ppunge and kick attacks instead of Swat attacks, you can easily do that without changing a single line of code. Let's look at what we cover in this course. We'll start by making a basic third person controller. We'll not use any assets for it, fill, build it completely from scratch because it's a good way to learn the fundamentals of gameplay programming. Then we'll start building the combat system on top of our third person characters fill. The ability to attack. The attacks will be architecture using scriptable objects. Ingenuity'll make it designer friendly and designers will be able to create and edit attack combos without changing any code. Then we'll start building the enemy AI. We'll act the enemy I using a finite state machine. It's a technique that's been used for building AI in games for the last 25 years. It's used in popular games like Last offers, Batman Archom series and many more. We'll build a finite state machine from scratch and create our enemies using it. We'll start by creating simple behaviors of the enemy like staying idle and chasing the player. Then we'll implement more advanced behaviors, like circling the player and attacking her in a coordinated way. We'll also implement more advanced features like counter attacks in the system. Throughout this course, you'll learn lots of game programming skills. You learn lots of intermediate level C sharp concepts like generic classes, dictionary link inheritance, et cetera. And you'll also learn to use mathematical concepts like technometry dot product cross, et cetera while building the system. You learn to design gameplay systems while keeping the usability and scalability in mind. The skills and techniques that you learn from this course will be really helpful for you if you want to pursue your career as a game programmer. All the models and animations used in this course are completely free. You'll be able to follow along the course without spending any extra money. The course also comes with the completed combat system project. You can use it as a reference while following along. This course is not for absolute beginners. You have no a little bit of Unity and C sharp to be able to follow along. But if you know the basics, you should be good to go. Who am? My name is Uttldleep. I'm a software engineer who has been building games and applications professionally for the last six years. I'm really excited to share my knowledge with you and help you in your came de journey. I hope you will join me in this course. 2. Section Intro: In this section will build a third person controller from scratch. Since we're making a third person combat system, the first thing that we need is a third person controller. And we'll build it from scratch in the section, because building a third person controller is a good way to learn the fundamentals of gameplay programming. If you're someone who already knows how to make a third person controller, you might feel like skipping the section. But I highly recommend you to watch this. Because in the section I'll be explaining some important concepts like root transforms of the animation and how to set up the root motion of the animation and all that. I recommend you give this section a quick watch. Even if you are familiar with building a third person controller. By the way, you may skip this if you wash the third person controller section from my unit Parco and Climbing System course. Because in that course I am building this same third person controller. If you wash that, then you may skip this. Otherwise, I highly recommend that you don't skip this section. Let's get started. 3. Project Setup: Hey phone. In this video I'll start by creating and setting up the Unity project, in which we'll build a combat system. I have my Unity up opened over here. I'll go ahead and create a new project by clicking on this new project button. Here we have to select a template. For the template, I'll select the RP. This is because we'll be using the shader graph to create shaders in this course. For that, we need RP or HDRP. It won't work in the standard three D project. I'll choose three DRP as a template. I'll just name this project something like Combat System. By the way, I'm using 2020 0.3 as the version. You can use any future version, and it should work fine. Let me go ahead and create the project by clicking on the Create Project button. Okay, so it'll take some time to create the project. I'll just pass the video and I'll get back to you once it's created. All right, so the project has been created. The URP project comes with some example acids. We don't need them. We're going to build everything from scratch. Let me go ahead and delete the example acids. And I'll also delete the polo containing the example acids. Okay, then we can also delete the tutorial info and the read me file. We don't need them. Next, let's create a new scene inside the scenes photo. We already have a scene over here, but I want to create a new one I could create and select scene to create a new scene. Let me just name this something like test scene. I'll double select to open it. Here I rather new plane game object under three D object. I'll select plane. This will act as the ground of our scene. All right, let me just reset its position so that it's at the center. I also want to make this plane a little bigger. I'll chain the X and Z scale to something like five. All right, we have a much bigger plane. Next, I want to change the material of the plane. If we use a plane material like this, then it'll be hard to understand if our character is moving or not. Let me create a new material for this. Under the Materials folder, I'll right click and create a new material. I'll call this Material Checkers. All right, under the surface Input we can change the texture of the material. So if you'll con on the base map you can select the texture that you want to use. I'll just use this default checkers texture that comes with Unity. All right, now we can track and drop this material to the plane to apply it. It's applied now, but the checkers are a bit big. I'll increase the tiling to ten to make the checkers smaller. That looks good. Now we have set up the scene to work with. Next we can start building our third person character controller. 4. Camera Controller: He. In this video we'll implement a third person camera that can rotate around the player like this. All right, so let's start creating it. Let's implement the third person camera controller. First I'll add a capsule to the scene, which we can use as the player for now. All right, let me name this player. I'll double click on it to focus. Let me just place it above ground. All right, now we want our camera to look at the splayer and rotate around it. Right? Let's go ahead and write a script to achieve that. All right, in the scripts foldo, we already have a script called Simple Camera Controller, but we are not going to use that. We're going to build our camera controller from scratch. All right, let me go ahead and delete it, then I'll create a new script called Camera controller. All right, let me get rid of all the default code in the script. In what you want to do is first we want to place the camera behind the player at a distance like this. All right, this is the player and this is the camera. We want to place it behind the player at a distance in the camera controller script. First, we need a reference to the object that we want to follow. Here I'll create a sized variable of type transform. I'll call this follow target. All right, next we want to place the camera at a distance behind our Pollo target. Right in the update function, we can set the position of the camera to follow target dot position minus the distance by which we want the camera to be behind. Right subtracts follow target position by a new vector. This vector will be zero in both x and y and the z. We should provide the distance for now. Let's say we want the camera to be five units behind the player. I'll just put five for the Z. All right, let's core hurt and see the result of this. First we need to attach the camera controller script to our main camera. All right, let me just drag and drop it over here. Then we need to assign the Pollo target object. Let me just assign the player as the follow target. Now let's go ahead and run the game. All right, So you can see that the camera is placed behind the player at a distance. We can actually minimize the game view and take a look at it. From the scene view, you can see that the camera is behind the player. It's sad, position is minus five. Since the players position is zero, it's placed five units behind the player, right? Just like we specified from the script. That's working, but it's not good to hard code numbers like this in the code. We should make this a variable and expose it in the inspector so that the designers can easily tweak these values without touching the code. Right? Let me create a new variable for that. All right? I'll make it a sterilized field so that it's exposed in the inspector. And this will be a float variable, I'll just call it distance and set its value to five by default. Okay? So now in here instead of hard coding five, I'll use my distance variable. Okay? So now if you go to here, we can change the distance value from the inspector, right? So let me just put it back to five. All right, now we are placing the camera behind the player at a distance. Next, we should rotate the camera around the player. When we move the mouse, right, we should rotate the camera both horizontally and vertically. But first, let's handle the horizontal rotation. How can we rotate the camera around the player like this? For that, all you have to do is just rotate this vector. This is that vector. If we rotate this vector by multiplying it with a rotation, then it'll be rotated like this based on the angle. Let's go ahead and try this out in red. To rotate a vector we just have to multiply it with a rotation. Let's say we want to rotate this vector by 45 degrees. For that first, we need to create a rotation of 45 degrees. I can do that by using con oiler. All right? In which axis should be rotated? The rotation here is horizontal, right? If you want to rotate something horizontally, then we should rotate it in the Y axis, right? In the anion oiler, I'll put zero for the X, 45 for Y, and zero for the set. This will create a rotation of 45 degree in the Y axis. Then to rotate this vector, all you have to do is just multiply this coaterion to this vector. All right? And this will rotate the spector by 45 degrees. Let's score T and see the result of this. All right, I'm going to play the game. Now you can see that the camera is still behind the player, but now it's at a 45 degree rotation, right? So this will be more clear if you look at it from the scene view. All right, so if I just go to the top view in the scene, you can see that the camera is placed behind the player at a 45 degree angle. All right, that's working as expected. Next we want to rotate the camera around the player like this, when we move the mouse horizontally, right? That is pretty simple to achieve. What we can do is we can create a float variable over here called rotation Y. Then in the update function, we can add the mouse x input into the rotation by vab. All right? I'll say rotation y plus or equal to input dot t axis, mouse X. All right, We'll be adding the joystick in the future, but during the implementation, let's keep this simple and use the mouse. Now in the cotton oiler, we can use rotation y instead of just hard coding fortify. All right, so let's go to it and see the wrestles. So you can see that as I move the mouse, the camera is rotating around the player. But right now it's not looking at the player, but it's still rotating around the player. All right, so you can get a better view of it from the scene window. Okay. Yeah, you can see that the camera is rotating around the player in a circle. Okay, So that's working fine. Next we should make the camera look at the target when we rotate around it. Right? That's pretty easy to achieve. All we have to do is set this rotation as the rotation of the camera. All right, first let me store this rotation into another variable so that we can reuse it. I'll call this variable target rotation. All right, here I'll multiply the vector with the target rotation. Then we can also set this as the rotation of the camera. I'll set the transform rotation to the target rotation. Okay, now the camera should also look at the player. Let's go ahead and test it. All right, now you can see that as rotate around the player, the camera is constantly looking at the player that's working. Now we're done with the horizontal rotation of the camera. Next, we should also rotate the camera vertically, like this, right? This is going to be just like the horizontal rotation. The only difference will be for vertical rotation, we should rotate it around the x axis. Here I'll create another variable called rotation x. Then we should rotate the camera vertically. When we move the mouse up and down, right to the rotation X, I'll add the mouse Y input or light level is copy this line and change it to mouse Y. This might be a bit confusing to some of you because we are adding mouse Y to rotation X and mouse X to rotation Y, right? But the reason for this is because for horizontal rotation, we should rotate around the Y axis. Vertical, we should rotate around the X axis. If that's confusing to you, take a minute or two to think about it and you'll get a hang of it. All right, Let's continue with the vertical rotation here. I need to add rotation X to the X of the cotton oiler. Now we should also be able to rotate the camera vertically. All right, let's go ahead and test it. Now if I move my mouse up and down, you can see that we can rotate the camera vertically. Okay? But in the case of vertical rotation, we want to clamp it to some limit, right? You should not be able to rotate all the way around the character like this, right? We should set the limit to how much we can rotate vertically. All right, we can easily limit that by clamping the rotation x value clamp available, we can use mathftclamp. What this function will do is it'll take a min and max limit. If the value goes beyond the limit, then it'll just clamp the value to the limit. In this case rotation excess, the value that we want to clamp. And then we should define the min and max limit. I'll create variables for the min and max limit and I'll make them sterilized field so that we can tweak it from the inspector. Okay, I'll call the first variable in vertical angle and let me set it to something like minus fortified by default. All right, and then I'll duplicate this line. By the way, you can duplicate a line in vital studio by using the control shortcut. All right, I'll duplicate the min vertical angle variable and create another one called max vertical angle. I'll set this one to press fortified degrees. All right, now we can clan the rotation x between the min vertical angle and the max vertical angle. Okay, so scored and tests. By the way, I'll just make sure that the min and max angles are correct in the inspector and I'll go ahead and play the game. Okay. Now, I can't move the camera above this limit. I'm clammed over here. If I go down. Okay. This minimum angle is a bit too much, but I'm clammed over here. I can't go beyond this point. Right? The clamping is working properly. We're done with the vertical rotation, But there is actually a problem right now. The camera is actually looking at the bottom of the player, right? It's not pretty obvious right now, but when you bring in an actual character model, the camera will be looking at the feet of the model and that will look really weird. The camera should actually look at the chest, the head part of the player. We can easily achieve that by adding an offset to our target position. Here I'll create a new vector two variable and I'll call this framing offset. Okay, Then instead of using the polo target dot position directly, I'll add the framing offset to the Pollo target position. All right, let me show this in a variable called focus position. This is the position to which the camera should focus. Okay, We can't simply add these two like this, because photo target position is a vector three and the framing offset is a vector two, right? We can't directly add them here. I'll have to create a new vector three. Then I'll have to pass framing offset X and framing of the taught by. Okay, so that solved the error. And now we have focus point here. Instead of using the follow target dot position, I'll use the focus position. Let's go to Unity and tests. All right, Right now it's still looking at the bottom because we didn't set the offset in the inspector. Let's try changing the framing offset from here. Here you can see as I increase the Y offset, our focus position gets higher and higher. So let me just set it to a value like one for now. This is further when we bring in an actual character. All right, so that looks much better, sex. We also need to limit the minimum vertical angle. This is a bit too much. We should not be able to go below the ground, right? Let me try setting it to something like -20 By the way, here you can see that the framing offset has been reset to zero. This is because we changed its value when we were in the play mode. Whatever changes that we make in the play mode will always be reset when we exit the play mode. All right, let me set it back to one now. Let's go ahead and test if the vertical angle is fine. Yeah, that's okay. Now we're done with the vertical and horizontal movement of the camera. All right. There is one more thing I want to add. Before I stop the video. I want to be able to control the speed at which the camera moves. That is pretty easy to achieve when we are updating the rotation x and rotation variables. From here, we can multiply the mouse input with the speed value. All right, I'll create a new float variable called rotation speed. And let me just set it to two by default. Okay? And then I'll just multiply the rotation speed with the mouse input. All right. So let me also do it in this line. Okay, So now we should also be able to control the rotation speed of the camera from the inspector. All right? It's true right now, but if you want, you can increase it to a higher value. Next, I want to hide the mouse. When we are playing the game right now, you can see the mouse when the game is being played. I want to hide that. To hide the mouse, we have a property called cursor visible. I'll set that property from the start function. Let me create the start function. Over here in the start function, I'll set the cursor visible property defaults. This will make the cursor invisible. Then we can also lock the cursor by setting cursor lock state to cursor lock mode lock. All right, so now we won't see the cursor when we play the game, All right? You can see that the cursor is not visible anymore. Now if you want to stop the play mode, you should first press the escape key, so this will make the mouse visible again. And then you can go ahead and stop the play. All right, so just keep that in mind, Now we have a decent third person camera. But there's one more thing I want to add. Some people prefer the camera direction to be inverted. Right? Let's add a setting for that in our camera controller script. Here I'll add two new polling variables. The first one will be called invert x, the second one will be called invert y. If the invert x is true, then we should invert the x rotation. We can easily do that by multiplying the mouse input with minus one. Right? What I'll do is I'll create two more variables for the invert value. First one will be called invert x v, the second one will be invert y al, okay? And we'll set its value from the update function. If the invert x is true, then the value will be minus one, and otherwise the value will be one. All right, let me store this into invert x val variable. Then I'll also do the same for the invert val. All right. Now we can multiply the invert X val with the mouse X input. We can also multiply invert Y val with the mouse Y input. Okay? So this should allow us to invert the camera movement from the inspector. I'll turn on invert X and invert Y. All right, now when we test, the camera movement should be inverted. All right, so now we have a basic third person camera set up. So I'll stop the video here. And in the next video we'll implement character movement. 5. Character Movement: Everyone in this video will implement character movement. It's going to look like this. The character movement will be related to the camera, just like we see in all third person games. All right, let's start the video First, I'll replace this capsule with an actual character. When implementing character movement, we won't be able to see the rotation properly if we're using a capsule. All right, let me switch this with an actual character. I'll be downloading the character from a website called Mimo.com This site has lots of good characters and high quality animations and they're completely free. I'll open up Xm.com You'll have to create an adobaccount to use this. All right. I'll go to the character section and download a character. The character I want to use is Erica. All right. This is the character I want to use. Click on it and then click uses this character. Once you do that, you'll be able to see the character in this window. By the way, you don't have to use this same character. There are lots of different characters to choose from. All right, I'll just go with this character. Let me click on the download button for the format, to select Px for Unity. Then we want the pose in the post itself. Just make sure these two options are correct. Then you can click on the download button and the character will be downloaded as an FPX filed. All right, so I've saved it to my textop, Now let's go ahead and import the character into Unity. Under Assets, I'll create a new folder called Models. This is where we'll put all the three D models. Next, I'll drag the FPX file that I downloaded into the models folder. Okay, so the model is imported. So I'll drag the model to the scene so that we can have a better look. All right, let me just get rid of the capsule now. Yeah, you can see the character model, but it doesn't have any textures on it. Fix a, select the model In the material stap, click on the extract textures button. All right, so we need to specify a folder in which the textures will be extracted. Here, I'll create a new folder for that. Let me call it text. All right, And I'll select this folder. Okay, so now we're getting this warning saying that no texture should be marked as novel map. Here, we just have to click on the Fixed now button and it'll automatically fix it for us. All right, so now we have the textures arson. Next let's implement the script to move this character inside the scripts folder. I'll create a new script called Player Controller. All right, let me open it up in Visual studio, and I'll also get rid of the default code in this script, we should move the player based on the input of the user. Right. First I'll get the input from the update function. Let me create the update function over here. Then I'll get both horizontal and vertical input. All right, let me store the horizontal input in a variable called H. Then I'll also get the vertical input, and I'll store it in a variable called V. All right, so we have the input. Next, let me create a vector based on these two inputs. I'll call this vector move input. All right, so this will be a vector three. The x value of the vector will be the horizontal input. The y value will be zero, and the z value will be the vertical input. All right, this is a direction in which we should move the player here. We have to do one more thing. We have to normalize this vector. So I'll use a normalized property to normalize this vector. What this will do is this will set the length of the vector to one. If we don't do this, then the diagonal movement will be faster than the movement in a single direction. That can be solved very easily by normalizing the vector. Okay, now we have the movement input. Next, we should move the character based on this input, move the character. I'll update the transformed position. To the position. We can add more input so that the character will move in the direction of the input. Then we should be able to control the speed of the moment, right? For that, I'll create a variable called move speed. Let me just set it to five by default here we should multiply the move speed with the moment input. All right, so now the character will move in the speed. And finally, we should also multiply this whole thing with timed or delta time so that the movement is frame rate independent. Okay, now the character should move based on our input. Let's score Unity and test it. All right, so first we should assign the player controller script to our player. I want to attach it to the model directly. Instead, I'll create an empty game object here called Player. All right, let me reset its position. Then I'll make the model a child of the player game object. Okay, I'm doing it like this because in the future we'll have to add more things to this player game object. All right, now we can go ahead and attach the player controller script to the player. Then in the camera script, the photo target reference will be missing because we deleted the capsule. Now let's go ahead and assign our player. All right, now let's go ahead and from the game. The camera is moving around the player, just like before. Now when we press the WASD keys or the arrow keys, the character should move. All right, so the character is moving, If I press the arrow key, it's moving forward. If I press the down arrow key, it's moving backwards and then it's also moving left and right when I press those keys. All right of the movement is working as we expected. But this is not how the character should move in a third person set up. Right now, when we press the forward input, the character is moving in its forward direction, but it should actually move in the camera's forward direction. In a third person controller, the movement of the player should be related to the camera. So to achieve that, all you have to do is multiply our more input with the rotation of the camera, right? This will make the movement flate to the camera. First, we need to get a reference to the camera from the script. Let me actually create a variable for the camera controller over here. All right, then I'll catch a reference to it from the awake function. Since the camera and player are attached to different objects, we can't simply use the ket competent function. Instead, we'll have to get the reference to the cameras game object. First, we can get the reference to the cameras game object by calling camera main property. Then on that we can call ket competent and get the camera controller. Okay, let me cast this to the camera controller variable. Now we can multiply the move input with the rotation of the camera. All right, so I'll get the rotation from camera controller transformer rotation. And then I'll multiply it with the move input. Okay, I'll store this in a variable called direction. I'll just say IR for a shot. Then here I'll use the movement direction variable instead of the movement input. This should rotate the movement input in the camera's direction. But there is actually a problem with this. Our character should only be able to move in the exit plane, right? It should only be able to move in the horizontal plane. When we multiply the move input with the camera's rotation, we should only take the camera's horizontal rotation, we should not take the vertical rotation. If we use the vertical rotation, then the player will also be able to move up and down. We don't want that unless you're making a player that can fly. Let me go to Unity and show you what happens when we use the complete rotation. All right here, the movement is related to the camera, but the player can also move up and down. If the camera is facing up like this, then the player will be able to fly. All right, so we don't want that here. Visually take the horizontal rotation of the camera. We can get the horizontal rotation from rotation y, right? What I'll do is in the camera controller script, I'll create a new property called plan a rotation. This will be the rotation in the exit plane or the horizontal plane. All right, in this property we should return a coternion. Soil create a coternion by using cotoniler. We should only consider the y rotation. We should not consider the extortation like we do over here. Soil pass zero for the extation, then I'll pass rotation variable for the y. Then I'll pass zero for the Zt. This will give us the plan ar, rotation of the camera. Now from the player controller, we can simply multiply the move input with the planar rotation. All right. By the way, if you're not familiar with properties in C sharp, I'll explain it real quick. Properties are pretty cool feature in C Sharp. Usually in most programming languages, if you want to return something like this from a class, you would create a public function. Usually you would create a public function, get plan rotation. Then from that function you would return this value, right? So this is how you usually return something from a class. But in C sharp, we have a cool feature called properties. Properties are just like a function. The only difference is they won't have this parenthesis that a function has, right? You don't have this feature in most of the programming languages. I just want to give you a quick explanation in case you don't know what properties were. By the way, if you want to use a function over here like this, it's shortly fine. I just like using properties since they are shorter. All right, let me get rid of the function now. The movement is only multiplied with the planer rotation. The character shouldn't be able to move up and down. All right, let's go unity and test it. All right, So the character is not able to move up and down, but it is moving relative to the camera. Now when I press the forward key, it's not moving in its forward direction, instead it's moving in the forward direction of the camera. Right? That's working fine. Next, when moving the character, the character should rotate and face the direction in which it is moving, right? We just have to set the rotation of the character to make it face in the right direction. From here, I also set the rotation of the character. We want the character to face in this move direction, right, But more direction is a vector. For the rotation, we have to pass a quaternion. We can actually get the rotation from a direction vector by using quaternion rotation function. We have to pass the directional vector in the parameter of this function. Okay? This will make the character phase in the direction in which it's moving. But we should only update the direction when the character is moving, right? How can we check if the character is moving? For that, I'll create a new variable called move amount over here. This variable will be a sum of horizontal and vertical input. If the move amount is greater than zero, then that means the character is moving and we can update the rotation. All right, but we can't simply add the horizontal and vertical input like this. We should remove the sine of the horizontal and vertical input, right? We don't care about the direction of the input, we only care about the amount. If the horizontal input is minus one, we should remove the sine and make it one. To remove the sine from a value, we can use the math at ABS function. Here, ABS stands for absolute, since this function returns the absolute value by removing the sine. All right, and let me also do it for the vertical input. And now if the move amount is greater than zero, then that means the player is moving. We can move the code to set the rotation inside this if we can actually move this line. Also, because there is no point in trying to move the character if the input is zero, right? I'll actually move these two lines inside this condition. All right, now the character should face in the direction in which it's moving. Okay, so let's score Unity and test it. All right, So you can see that the character is facing the move direction, okay? But the problem is the character is rotating instantly, right? That looks really weird. We don't want the rotation to be instant, we want it to rotate smoothly. So let's look at how we can achieve that. To make the rotation smooth, we should not set the rotation directly like this. I'll this rotation in a variable called target rotation. All right, here, instead of setting the rotation directly, I'll store it to the target rotation variable. Then outside this condition, we can slowly change the current rotation of the player to the target rotation, right? Slowly change one rotation to another. We have a function called rotate towards. All right, in the first parameter, you have to pass the from rotation. Here. The from rotation will be the current rotation of the player. Then two rotation will be the target rotation. Finally, in the third parameter, we should pass the amount by which we should change the rotation. Using the third parameter, you can control how slow or fast the rotation change should happen. I'll actually create a variable for that called rotation speed. All right, I'll set its value to something high like 500. By default, the reason is because the function expects the rotation amount as an angle in degrees. Here, 500 is the angle of rotation. All right, now we can pass it as the third parameter. Then we should also multiply it with time delta time to make it frame rate independent. Finally, we should set the value returned by this function to our transform rotation. All right, so this will smoothly rotate the player instead of rotating it instantly. By the way, let me split this into two lines because I don't like lines that are really long. Okay, now let's go ahead and test if the rotation is working. I'll just select the player and make sure that the rotation speed is 500. All right, now let's go ahead and test it. Okay? Now it's rotating smoothly. You can actually play with the value of rotation speed and find a speed that you like. I think this is fine. We successfully made our character move based on the input. Next, we should implement animations when the character moves. We'll implement that in the next video. 6. Animation Setup: In this video, we'll set up the animations that we need. We'll look at a concept called Human Art retargeting Unity, which will allow us to reuse the same animation on multiple models. First, let's download the animations that we need. I'll be downloading all the animations from Maximo, the same place from which we downloaded our character. Here you also have animations. If you click on this animation stab, you can browse all the animations available in Miximo. All right? By the way, before you start selecting and downloading the animations, make sure to select the character that you downloaded in the previous video. In my case, the character is Erica. All right, so I'll select the character and click on use this character, All right. So make sure do this before you start downloading the animations. This is important because when you download the animations, Ixia will automatically make it compatible with the character that you selected. All right, now let's look at the animations that we need. First, we need an idle animation. Here, I'm going to search for idle. You have lots of variations. I'll just go with a simple title like this one. All right. By the way, you have few settings over here, you can play with it if you want to modify the animations For this animation, the hand of the character is really close to the body. If you want to have more space between the hand and the body, then we can increase the character space. Let me increase it to something like 68. All right, that looks better. I'll go ahead and download this animation while do you have a few settings over here for the format. Make sure you select Px for Unity, just like we did for the character. Then you can download it with the skin. Without the skin. If you select with skin, then it'll also download the character that we selected. In our case, we have already downloaded the character. We don't want to download that again. I'll set it to without skin. All right, then for the frames per second, leave it at 30 And leave the key frame reduction at none. I'll Right to make sure these settings are right. And then click on the download button to download the animation as an FPx file. I'll just name this Idly and save it. Okay. Next we need a walking animation. So let me search for walking again. We have lots of variations. Let me try this one. All right, This one looks okay for the walking animation. Make sure to check the in place checkbox. All right, once we check that the character will only play the animation, she won't actually move while playing the walking animation. All right, in our game for character movement, we don't want animation to control the motion of our character. We want our code to control it. We wrote the code for it in the previous video. We should check the in place checkbox to remove any motion in the character. All right, so now I'll go ahead and download it. I'll use the same settings as before. Let me just name this one Walk. Finally we need an animation for running. Let me just search for run. Okay, I'll just go with this one again. We have to check the in place checkbox to make sure that we don't have any motion with the animation. All right, now I'll go ahead and download this. I'll call this one run. All right, now we have the animations. So let's go ahead and import them to Unity. Unity in the Assets folder, I'll create a new folder called Animations. Then I'll import three animations that we download it right now. Okay, now you can check if an animation is working by selecting the animation and then selecting the animation tab at the bottom, you should be able to review the animation. But right now it says, we don't have a model and we have to drag a model to this preview area. Let's go ahead and drag our model into the preview area of the animation. All right, so now if you press the Play button, you can see that the animation is working on our model. All right, but the reason why this animation worked with this model by default is because Maximo made this animation compatible with our character, since that was the character that we selected in Maximo, right? The problem is if we bring in another model to our project, the animations might not work on them. Let me show you by importing another model. All right. This is another character model that I downloaded from Maximo. Let me drag him to the inspector and I'll check if the animations are working on this model. Okay, so if I drag this model onto the preview of the animation, you can see that when I press the play button, the animation is not playing on the character. These animations won't work on other characters. That's a problem. We don't want to download separate animations for separate models. We want to be able to reuse the same animations. Luckily, it has an EC solution for this. Before we look at the solution, let's look at why the animation is not working on different models in the first place. If you expand the game object of our character model, you can see that it has bones under it. All right, so it has bones for all the parts in its body. Now if you look at the second character, it also has bones. But the problem is the names of these bones are different, right? Usually the models that are created by different artists will have different bone names. But the way animation works is by modifying the position and rotation of these bones. If you expand the Ok animation, you can see the animation clip over here. And if you click on it, it'll open the animation clip. In the animation window here, you can see what this animation is doing. This animation clip is modifying the position and rotation of the bones of the character and that's how it's achieving the animation. Right here, you can see that this animation uses the bone names of this character, right? The bond names of the pod character is different and that's why the animation is not working on the ipod character. If you rename all the bones of the ipod character and make it as same as this character, then the animation will also work on the ipod character. But that solution is really tedious, right? We have lots of bones for a character, and renaming each and every one of it is really hard. The good thing is Unity provides us with a solution in which we can solve this with just a few clicks. The solution is humanoid re targeting. Basically what we'll do is we'll map the bones of all the characters to a standard set of bones that Unity can understand. All right, we'll do that for all the characters and all the animations. Once that's done, the animations will work with all our characters. All right, let me show you how to do humanoid re targeting for this. First we have to select the character, then you have to go to the tab here you have to change the animation type from generic to humanoid. All right, this works by creating an avatar. Avatar is a thing that maps the bones of our character to the standard set of bones. In the avatar definition, we have to select Create from this model. Then all you have to do is hit Apply. All right, you can see the tick mark over here. That means Unity was successfully able to map all the bones. In case Unity was not able to map it automatically, then you'll have to click on the configure button. This will show you all the mappings that were done by Unity. All right, you can see that over here, if some bones are missing from the mapping, then you'll have to manually drag and drop it over here. All right, so I click on the done button to go out of the avatar. You can also see Avada over here. This is my character inside it. We have Avada now. All right, now we should also change all our animations to humanoid. Let's go ahead and do that first. Let me just select the work animation in the rig tab. I'll change this to humanoid. Then for the Avada definition we have to select copy from Avada in the case of animations. Then we have to select the avatar that we created earlier. All right, let me go ahead and assign that avatar. Now we just have to hit Apply. All right, we have to do this for all the animations. We have to make them humanoid. Let me select the other two animations and also make them a humanoid animation. All right, now the animation should work on our Erica character. All right, then it'll also work on the bot character if we turn it into a humanoid, let's go ahead and do that in the tab, I'll change it to humanoid since this is a model I'll create from this model. That definition then I'll apply. All right, so it was successfully able to create the avatar and map the bones. Now the animations should also work on the board character. So let's go to the animation tab and preview the animation on the board character. Okay, so the animation is working fine. That's really easy to set up. All you have to do is just change your characters and animations to humanoid when you import them to your project. If we preview our animations, you'll see that we have a slight problem. Let me just make this big so that you can get a better view. All right, here at the bottom of the player's feet, you can see a circle. The circle is moving right. If the circle is moving, that means the animation has some motion in it. But in our case, we don't want to use the motion of the animation. We want the character movement to be controlled from the code completely. We have to get rid of this motion. By the way, if we drag our other character, the main character that we are going to use here. Also you can see the circle is moving. This motion is called root motion. It's really useful in some cases. For example, for an attack animation where the character is jumping and swinging at the sort. We could move the character from the animation itself instead of moving it from the code. But in the case of idle walk and run animations, we don't want to use root motion. We want the motion to be controlled from the code itself. All right, the problem is when we turn our character into a humanoid character, it'll automatically set up the root motion. That's what's causing this motion in the animation. All right, we can easily fix this by using these three options here for the root transform rotation, Root transform position. By root transform position exit, we should change all of them to original. All right, all of them should be original. And then we should also select Bacon to pose for all of them. All right, now you can see that the circle is not moving anymore. It's stationary. These options are really useful. We'll explore these options more in the future when we implement attack animations. But for now, just keep in mind that if we don't want to use root motion, then check bacon to pose for all three of these. And then also change there based upon two original. All right, I'll go ahead and apply. Now the circle is stationary now let's go ahead and do this for the other animations also. Unfortunately, we can't do this for multiple animations at once by multi selecting them. We'll have to do it one by one first. Let me do it for the run animation. All right, so I'll check bake, interpose, and change based upon two original for all three road transforms. All right, then I'll hit Apply. By the way, we also want these animations to. Let me also select loop, time and loop to loop these animations while we're here. All right, now let me hit Apply. Now let me do the same for the idle animation. All right, let me also check loop time and lopo so that the animation will loop. All right, finally let me also turn the loop time and loopose for the walk animation. Now we're done with the set up of our animations. Next, we can use these to animate our character when moving. 7. Adding Animations to Character: In this video, we'll look at how to add animations to our character. Your character movement will look like this once you add animations. Let's look at how to do this. We'll play the animations on our character. We have to create an animator controller. Let's go ahead and create that. On the Assets folder, I'll create a new folder called Gain. All right, this is where I like to put all my prefabs and scriptable objects and animated controllers. Basically all the things that a designer would want to use inside this folder. I'll create another folder called animator. I'll create my animated controller. Over here, you can see animated controller. I'll name this character Controller. Okay, so now we can double click on it to open the animated controller. Animated controller controls what animation should be played on our game object. We can drag all our animations in here and then define what animation should be played based on the parameters. Let me drag one of our animations in here. I'll just drag the run animation. Let me rename this to run. The first animation that you drag into the animator. Controller will be the default animation that will be played. If I also drag the other animations, you can see that their color is different. The run animation is in orange color, right? That's because this is the default animation. Now if we attach our animator controller to our character, then our character should the run animation by default. To attach an animator controller to the game object, we have a component called animator. All right, in this component we can specify which animated controller that we want to use. I'll assign the animated controller that we created. Then we also need to assign the avatar of the character. The avatar of this character is called Erica Archer, Avada. Let me assign that. Now when we run the game, our players should play the running animation. All right, you can see that it's working fine. Now let's also try attaching our animator controller to the second character just to make sure that the animation is also working properly. On the second character, on the Y board character, it already has an animator component attached to it. Unity Dust is automatically when you turn a character into a humanoid character, also over here you can see that the avatar has automatically been assigned. Okay, we just have to assign the animator controller the Y board character should also play the running animation. All right, it's also playing the animation. Our animations are working fine on all the characters. Next, we don't want our character to simply play the running animation. We want to play different animations based on the speed in which the character is moving. If the character is not moving, then we want to play the idle animation. And then if the character is moving slowly, then we want to play the walk animation. And then if the character is moving fast, then we can play the run animation. All right, the animated controller, there are different ways to control what animation should be played. But in the case of movement animations, I want the animations to blend smoothly. For example, instead of just switching from the walk animation to the run animation, I want to blend between them based on the speed. To achieve that, I'm going to use a blend tree. Let me go ahead and delete these three animations. All right, now I'll create a blend tree to blend between our animations. All right, I'll name this blend tree Locomotion. And then we can double click on the blend tree to open it. In the blend tree we can add multiple animations. And the blend tree will blend between these animations based on the value of this parameter. All right, in our case, we want to add three animations here. I'll add three motion fields. Okay, so the first one I'll assign the idle animation. And by the way, we can't directly dragon drop the Px file of the animation here, we can only assign the animation clip to it. All right, so we have to assign this animation clip. The first field we have to assign the idle animation. Then to the second field we have to assign the Ok animation. All right, finally to the third field, we'll assign the front animation. Okay. Now in the preview window, if you play the animation, then the character will be in the idle animation. But now if you change the blend, then it'll slowly start walking at 0.5 It'll play the walking animation in the actual speed of that animation, right? That's because here we have thresholds. The threshold of idle is zero, walking is 0.5 and running is one. All right, when it's at zero, it'll be in the idle animation. When it's at 0.5 it'll be playing the walking animation. When it's one, it'll be playing the running animation. All right, but the cool thing here is when the blend is between 0.5 and one, it'll play fast walking animation like this. This is a blend between our walking and running animation. This is why blend tree is really useful. Also, if I try setting the blend somewhere 0-0 0.5 then it'll also blend between the idol and the walk animation. All right, you can see the character is doing a really slow walk, which is not really useful for us. But I just want to show you how the animation is. Blend the blending between the walk and the run animation that is really useful By the way, you can also change the threshold of different animations. Right now it's not editable because the automate threshold checkbox is turned on. If you turn it off, then you can edit the threshold values. I'll just set the threshold value of the walking animation to something lower like 0.2 The reason is because I want my character to start playing the walking animation as soon as it starts moving. This is just a personal preference. You can play with this value and set it to one that you like based on how you want your third person control. All right, now we just have to set this blend parameter from the core and the character should automatically play the correct animation. All right, but first, let me actually rename this blend parameter to something meaningful. I'll call this amount that makes sense. If the amount is zero, then the character should be playing the idle animation. Then as we increase it, the character should start walking and running. Right now, let's go ahead and set this parameter based on the character's movement. Let me open the player controller script. Okay, so to set a parameter to the animator, first you need to get a reference to it. So I'll cash a reference to the animator from the away function. I'll just use the cut component function to get the reference of the animator. Now we should set the amount parameter in the animator. We're already calculating a value called amount over here, so we can set the same value to the animator. To set a value to the animator, pick animator set. When you type set, you can see that we have lots of options. In this case, the more amount parameter is actually a float value, right? So here we have different types of parameter. More amount is actually float. You can see that its value is floating point. To set the more amount from code, we can use the set float function. In the first parameter, we should provide the name of the parameter that we want to set. In this case, the name of the parameter is more amount. Then in the second parameter, we should pass the value that we want to set. In our case, we are already calculating the value over here. Let me just pass that as the second parameter. Okay, by the way, one thing I want to address is the more amount parameter should be 0-1 right? But here, the value that we are calculating, it can be greater than one. For example, if both horizontal and vertical input is one, then its value will be two, right? So we have to make sure to clamp this value 0-1 to make sure that the animations are selected correctly. All right, clamp a value 0-1 We have this function called clamp 01. All right, we just start to put the value in this function like this. Okay, now our character should play the animation correctly, based on our movement. Let's score Unity and test that. By the way, let me get rid of the Wipeout character. I just brought it in just to show you that the animations will work on multiple models. All right, so let's go ahead and test. Now when we move, you can see that our character is playing the animation correctly. All right. Our third person control is looking so much better when we add at the animations. But if you look at how the animation stops, it's stopping really fast, right? It doesn't look very realistic. The reason for that is because when we start pressing the input, the more amount becomes zero. Immediately, when the more amount is zero, the character will start playing the idle animation immediately. We can easily make this smoother by adding a damping when setting the more amount. If you look at the third parameter of this function, you can see that we have a parameter called dam time. If we add this parameter, then the animator will smoothly change the parameter to this value instead of setting it instantly. All right, for the dam time, I'll pass a small value like 0.2 Then when we pass the dam time, then we should also pass the delta time in the fourth parameter. So I'll pass time delta time in the fourth parameter. Okay, so this should smooth out the animations for us. So scored humity and test. All right, so now you can see that the animation is not stopping instantly, it's slowly coming to a stop. Right? So yeah, now we have a pretty decent third person controller. A small problem that we have here is the camera is going below the ground. So let's fix that by reducing the minimum vertical angle of the camera. Okay, let me try setting it to minus ten. All right, so now the camera won't go beyond this point. Okay? Yeah, our third person control is looking pretty good. There is one thing I missed to do while setting up the animations. So if you look at the ideal animation, you can see that it is 8 seconds long and has 250 frames. That's a bit long. And we don't want the idle animation to be that long. If you look at other animations like run and walk, you can see that they are much shorter. Having such a long animation can cause problems for us in the future when we transition to other animations. We can make this shorter by reducing the end frame. We can just drag the slider to reduce the end frame. I'll just make the end frame 30. All right, now the animation is only 1 second long. Let's apply the change, Let's just test to make sure that everything is working fine. All right. So things are working just like before. I'll stop the video here. In the next video, we'll look at how to set up collision and gravity for our character. 8. Collisions and Gravity: Right now, we don't have any collisions in our game. So let me add a cube to our scene so that we can test collisions. Okay, let me just make this cube a little bigger. All right, now if we try walking through this cube, you can see that we don't have any collisions. We need to handle that. To handle collisions, we have two options. We can either use a rigid body or we can use the Character Controller. For this project, I'm going to use a Character Controller. Let's look at the documentation of the character controller to understand what it does In the docs, you can see that the character controller allows moment constrained by collisions. It is not affected by any external forces. This is an important point. If we are using a rigid body, it'll be affected by external forces. We don't want that for the player in our game. That can cause problems. In the future, we're going to go with a Character Controller instead of rigid body. All right, let's go back to Unity and let's add a Character Controller to our player game object. Let me search for Character Controller. All right, now in the scene view, you can see that there is a capsule collider. The character controller comes with a collider. We can adjust the size of the collider by changing these values. I'll change the height to something like 1.7 since that's the height of our character. Next we need to add an offset in the y so that the collider fits the height of the character. Usually, I like to set the y a little above the half of the height. The half the height is 0.85 I'll increase it a little and make it 0.9 All right, this will make sure to keep the player's feet grounded. Next, we don't want the radius of the collider to be this big, so I'll set it to something small like 0.2 Okay, One more thing I like to do. I like to add a little z offset somewhere around 0.08 The reason for this is because our player will always face the direction in which it is moving. Collisions will mostly happen in the front side of the player I like to of the collider towards the front side. All right, we have set up the character controller next. When moving the player from the player controller script, we should not move it directly by updating the player's position. Instead, we should use a move function of the character controller that will make sure to constrain the movement by collisions. We should use character controller move function instead of this. First, let's get a reference to the character controller. All right? I'll catch a reference to it from the function. Okay, so now to move the character, I'll use character controller to move function. And for the motion vector, we can pass the same value as before. Let me just cut that and paste it over here. All right, I can get rid of this line. This will move the character just like before, but it'll also constrain the movement by collisions. So now let's coinity and test if the collisions are working Okay. Now you can see that we can run to the cube. All right, so the collisions are working fine. Next, we should handle gravity and make the player fall when the player is in the air. Right now if we place the player in the air and if we run the game, you can see that the player is not affected by the gravity. She can basically walk in the air. All right, the character controller is not affected by any forces like the gravity. We have to manually apply the gravity to our player from the player controller script. To apply the gravity and make the player fall. First we should check if the player is in the ground or is in the air, right? We should really make the player fall. If the player is in the air, the character controller has a field to check if the player is standing on the ground or not. The name of the field is grounded. This T if the character is standing on the ground. But the thing is I find this field of the character controller to be really buggy. Sometimes it can return wrong values. I don't like using this. I like to manually check if the player is in the ground or not biasing physics. If you look at the implementation of the third person controller in units, data assets, you'll see that even in this project, they are not using the grounded property of the character controller. Instead, they are checking it manually by using physics. Let's also check that man bioing physics. Let me get rid of this line. All right, below the up plate function, I'll create a new function called ground check. From this function, I'll use the physics check sphere function to create a small sphere at the player's feet. And check if there are any colliders overlapping in that sphere. Okay, here you can see the description of this function. It will return if there are any colliders overlapping in the sphere that we defined. Okay, to create this speer, we have to pass a few things. We have to pass the position, the radius, and a layer mask. The layer mask is optional, but it's really important to use a layer mask when you're doing any physics operations. It'll make the operation a lot more efficient. If we provide a layer mask, then this function will only check for colliders in that layer. Okay, I'll define serialized wheel variables for these three varus so that we can control them from the inspector. All right, so first let me define a variable for the radius of the speer. I'll call this crowd check radius. Okay? I'll set it to something like 0.2 by a default. Next for the position, we don't need a separate variable for the position. We'll be using the position of the player itself. But it would be nice to add an offset to the position. I'll create a vector for the position offset. All right, let me call this crown check offset. Next we also need to define available for the layer mask that we need to check. I'll create a layer mask over here and I'll just call it ground layer. Okay, now in the check sphere function for the position, we can pass transform dot position. But we also need to add the offset, right? What we can do is we can transform the offset point based on the player's current position. We have a function for that called transform point. What this will do is this transform the position from the local space to the world space. And it'll transform it relative to the transform that we're using here. Okay? In this case it'll transform it. Related to the player I transform, transform point for the point. I'll pass the ground, check off it. Okay, we have passed the position next. Let's pass the radius. All right, and finally we'll also pass the ground layer. Okay? So this will check if the player is standing on the ground or not. It's actually create a variable to store the value of this function. Here, I'll create a balling variable called is grounded. Okay, And I'll store the value returned by this function into the grounded variable. All right, so now all you have to do is call the ground check function from here. And after that we'll know if the player is grounded or not from the grounded variable. Okay, So let's actually use a debug dot log so that we can test if the player is grounded or not. Okay, so next I'd like to visually see the sphere in the scene. This will, allows to set the offset and radius properly as if there are any issues with the ground Check. It allows to understand what's happening. We can achieve that by drawing a gizmo. Gizmos are the shape that you see in the scene. For example, if you select the player, you can see the collider, that's actually gizmo. We can draw a gizmo like that for the ground check sphere. To draw a gizmo, we can do that from two function. The first one is rogsmos, second one is ragsmos selected. Rag ism selected will only draw the gizmos if this game object is currently selected. Let's use that. We can draw gizmo by calling gizmos draw spear function. All right, for the center, we can pass the players position offset by the ground check offset. For the radius, we can pass the ground check radius. Okay, This will draw the Chismo. We can also specify the color of the gchismo by setting the color before the draw function. I'll set kismotat color. I want the color to be something like a green. In the RGB value of the color, I'll pass zero for red, one for green, and zero for blue. Okay, and I also pass 0.5 for the alpha because I want the spear to be a little bit transparent. All right, so now it should draw the ground check spear when we select the player in the scene. Okay, you can see that it's drawing the ground check sphere. Let's ad just these values. 0.2 is okay for the ground check radius. For the ground check offset, I like to put the y value at half of the radius. I'll make it 0.1 All right. I also like to give a little bit of offset in the Z so that the sphere covers the feet around 0.07 should be fine. All right, so now the sphere covers the feet of the player. Next need to assign the ground layer. What I'll do is I'll add a new layer called obstacles. All the obstacles like the ground and the cube over here, all those will be in the obstacle layer. All right, so let's assign the plane to the obstacle layer. I'll also assign the cube. Okay, now for the ground layer, we can just pass the obstacles layer. All right, that's all we have to do. So let's go ahead and check if the ground check is working. All right, right now since the player is in the air, you can see that the scrounded value is false. But if I go to the scene view and bring the player down to the ground, you can see that it becomes true. So our ground check is working properly. Now we know if the player is grounded or not. Next, if the player is not grounded, we should apply the gravity and make the player fall right. What we have to do is to the move function of the character controller. We should also pass the vertical movement of the player. All right, if the player is grounded, there won't be any vertical movement. And otherwise we should apply a vertical movement to make the player fall down. Okay. The first thing I'll do is I'll move this line out as the condition. The reason is because the vertical movement should happen. Even if we are not pressing any input for the moment, right? Even if you're not pressing any keys, the player should fall down. I'll move outside the condition. Then what I'll do is I'll put the movement vector in another variable called velocity. Let me define velocity over here. All right? And then we can use the velocity variable over here. Now we can also set the y component of the velocity if the player is falling. All right, if the player is not grounded, then we can apply a velocity over here to make the player fall down. By the way, guys, if you don't know what velocity is, velocity is just the speed of something at a certain direction. All right? If you say a car is moving at 40 kilometers/hour that's a speed. But if you say it's moving at 40 kilometers/hour in this specific direction, then that is the velocity. It's just a speed with the direction. All right, we have to set the y component of the velocity to make the player fall. If you know how gravity works, you'll know that when something falls, it'll not fall at a constant speed, right? Instead, its speed will keep increasing throughout the fall. To be more accurate, every second the speed of the object will increase by the gravity. We can't set a constant value here for the y velocity, we need to keep increasing it. What I'll do is I'll create a new variable to keep track of the y speed. So let me create a float variable called y speed. All right, then if the player is falling, then we should keep increasing the speed by the gravity, right? If the player is grounded, we don't want to do anything. Now, we want to increase it if the player is falling, right? We want to increase it from the L's part of this condition, okay? If the player is falling, then we should add gravity to the Y speed. So we can get the gravity in our game by using the physics gravity property. We only want a Y component of the gravity. I'll just get the Y. This value is actually set from the project settings. If you could edit and select the project settings in physics, you can see that we have gravity. This is where the gravity of the game world is set. All right, here, if the player is falling, we want to increase by speed, by the gravity. But we should also multiply this time, delta time. This is because the Y speed should increase by the amount of gravity every 1 second, right? But the update function is not called every 1 second, it's called multiple times in a second, right? We have to make sure to multiply the gravity by the delta time, which is nothing but the value that has passed since the last frame. Now we are increasing the y speed. If the player is not grounded, let's set the y speed to the y component of our velocity, all right? And then if the player reaches the ground and is grounded, value becomes true, then we should reset the y speed back to zero, right? But what I'll do is instead of resetting it back to zero, I'll reset it to a small value like -0.5 The small value will make sure to stick the character controller to the ground. All right, this should make the player fall down if the player is not in the ground. Let me just scratch rid of the debut lock. Let's go ahead and test if the player is falling. All right, you can see that the player fell down. The gravity was applied correctly. Let me also try placing the player over this box just to test how it falls from such objects. All right, first we'll fall to the box. We can move from here, but if we move past the ledge of the box, then the player will fall towards the ground. Okay, so if that's not working for you, there are a few things that you have to check. So the first thing to check is the value of the ground check radius and the radius of the character controller should be almost same. If you make the character controller radius a higher value, then you'll have a bug where the ground detection will not detect any ground. But since the character controller is bigger, it won't allow the player to fall down. All right, so that's one thing to keep in mind. The radius and the set offset of the ground. Shakespeare and the character controller should be similar. They don't have to be exact same, but they should be in the same range. All right, next I just want to organize the player controller inspector a little. I want some segregation between the speed variables and the ground check variables. We can easily do that by adding a header above the ground check variables. Let me add the header attribute. I'll just call this ground check settings. Okay, now there should be some segregation between the variables in the inspector. Okay, so yeah, we have handled collisions and gravity in this video. All right, but right now the player can still move and play the back animation when she's falling. We'll be fixing those in the future, but right now, this is a good start. Next, let's set the skin with property of the character controller. This is a really important property if you go to the documentation of the Character Controller, and if you switch to the manual, the manual will have more detailed explanation when compared to the scripting API. Here we have a detailed explanation of all the properties. If you look at the skin, skin width allows other colliders to penetrate the character controller a little. This is used to reduce jitter and it also prevents the character from getting stuck. Recommends setting this to ten percentage of our radius. In our case, the radius is 0.2 The ten percentage of 0.2 will be 0.02 All right, I'll set the skin with 2.02 Next, we should change the y of the center based on the value of the skin width. Earlier I told you that y should be a little above half of the height for the character's feet to be on the ground. If you want to be more accurate, we can set the center to half of the height plus the skin width. All right, half of the height is 0.85 the skin width is 0.02 If we add that, we'll get 0.087 This will place the feet of the player on the ground perfectly, so let's go ahead and test to make sure that it's working fine. All right, so you can see that the feet is planted on the ground perfectly. Okay. I'll stop the video here. In the next video, we'll add controller input so that we can control our player with the joystick. 9. Controller Input: In this video, we'll set up controller input so that we can control the player with joystick. If you connect the joystick and desk the game, you can see that we are able to move the player using the left and locks stick. But we are not able to control the camera rotation using the right and locks stick. All right, if you look at the player controller script, here we are Using the horizontal and vertical input to move the player. It automatically sets up the horizontal and vertical input for the joystick. That's the reason why we are able to move the player with the joystick. You can actually see the input set up in the Project settings. All right, so if you go to Project Settings and select Input Manager, here you can see all the inputs that Unity defines by default. Here we have horizontal and vertical. Over here we have another horizontal and vertical input. Right, They are defined two times. The first one is defined for the keyboard. Here it uses the left and right keys. The second one is defined for the joystick. All right, here it uses the x axis of the joystick. Like this, we should set up all our inputs for the joystick. We want to be able to control the camera using the right and locks stick, right? If you look at the camera controller script right now, we are just using the mousex and mousey input for controlling the camera. Instead of this, we should set up a new input over here. And we should set it up for both mouse and joystick. Here, I'll create two new inputs called camera X and camera Y. I can just duplicate this mouse input to create a new input. We can try, click and select duplicate element. All right, I'll name this as camera X. We want this to be controlled by the mouse. We'll create another one for the joystick here, the type should be mouse movement. I'll change the axis to X axis, because this is camera X. All right, now we can just duplicate the camera X and we can create camera Y. Here, the axis should be Y. All right, next, let's create camera X and camera Y for the joystick, as well as just duplicate this camera Y element. Let me rename it to camera X. The type of this we should be joystick axis. For the axis, we'll select the fourth axis. The fourth axis is the horizontal axis of the right and locks stick. All right, now in case of joystick, we also need to tweak a few settings over here. Let's look at how the left and lock stick is set up for the horizontal input. Here you can see that the sensitivity of the input is one for the value of the dead. They're using 0.19 We can also do the same for the right lock stick for our camera X input. So I'll change the sensitivity to 10.1. Will be a perfect value for mouse, but it'll be really low for an lock sticks. Let's change this to one. We'll also change the value of dead to 0.19 this will be the dead zone. If the value is below it, then it'll be mapped to zero. All right, we have set up the camera input for the joystick. Next, let's duplicate this and create the camera Y input. All right, the Y axis of the right, an lock stick is the fifth axis. Let's change the axis to fifth axis. All right, that's all we have to do. Now we have a new input which can be controlled by both the mouse and the joystick. Let's use this input for rotating our camera in the camera control instead of using mousex and mousey fee, camera X and camera Y. All right. Now we should also be able to rotate the camera using the right analog stick. So let's go ahead and test that. All right. I'm also able to rotate the camera by using the right analog stick. Okay, now we can also control our third person controller using a joystick. I'll stop the video here and I'll see you the next video. 10. Performing Attack: He run. In this video, we'll start building our combat system and we'll make the player perform the attack animation. When we press input, first we need to find the animation for the attack. So let me go to Mixmo.com and with the Erica Archer character directed icon animations. And I'll search for, okay, we want a slash animation for our attack over here. We have lots of slash animations. I'll just use this one. Okay, so this is one I want to use. Let's go ahead and download it. Okay, make such a fix for Unity for the format. We can download it without the skin because you already have it. Okay, go ahead and download that. Once it's downloaded, we can import it into Unity. Here in the animations folder, I'll segregate the animations into different folders to keep things organized. Firstreate folder called locomotion. These three animations will go inside Locomotion. Okay? And then I'll create another folder called combat and begin bringing our new animation into this folder. Let me drag and drop it over here. Okay, we have to rig this animation to be able to view it'll. Go to the rig tab and change animation type to humanoid. I'll copy from Maamionucela because that's what we used in mix for previewing the animation. Okay, let me go ahead and hit a P. Now we should be able to preview animation if we just drag and drop our player into the preview window. Okay, the animation is a bit weird now, so we can fix that by enabling the root motion of the player's animator. Okay, so now it looks much better. Next, if you look at the animation settings here, we can change the based upon to original. For all the root transforms. This will take the root motion from the original animation. Okay, We can remove any unwanted root motion in the y axis. We can also remove any unwanted rotation by selecting ba interpose. Okay? If you want weak interpose for the exit root transform. I guess that won't be a problem because I don't mind if the player moves a bit forward, general attack. With this animation, the player is not moving forward because after performing the attack, she's coming back to the original position. So that's why we have green over here for the loop match. In this case, it really doesn't matter if we turn on the baking to post or not for the exit axis. But for most attack animation, we want this to be turned off. Because we want the player to move in the exit plane while performing the attack. Okay, so let me go ahead and apply this. This is how our animation will look. In order to play the attack animation, we have to first add this into our animated controller. Let me open my animated controller here. I want to add my attack animations in a new layer. From here, we can click on this plus button. We can add a new layer called over right layer. Yeah, I like to keep all my attacks animation in the over right layer. Basically, pup on this layer to any animation that is currently being played in the base layer. Okay, so to do that we have to click on the Settings button and increase the weight to one. Now since the override layer is below the base layer and since its weight is one, it'll completely override any animation that's being played in the base layer. Okay, now in here first cell, create a empty state. Let me just call this empty. In this state, no animation will be played. And we want to overwrite what's being played in the base layer. Okay? Most of the time the overright layer will be in the empty state. But when we want to perform an attack, we'll play an animation from this layer. Okay, let me go ahead and copy our animation into the overright layer. I'll just to, to keep things short. Okay, And once this animation is complete, we want to make a transition back to the empty state. All right, so this is how I want to set up my animator. By default we'll be playing the locomotion animation, but when we perform an attack, we'll start playing the slash animation and we'll ate the locomotion animation that's being played in the base layer. Okay, we're done with the set up of our animator. Next let's go ahead and write the script for playing attack animation. When the user presses an input, the scripts folder here, let me segregate the scripts into different folders so that it's organized. It's a first Ilgtd folder called these. Two scripts are going to be inside the player. Okay, recompile the code. Next I'll create another folder called Combat system. All right, all the scripts for the combat will be inside this folder. We'll start by creating the script for performing the attack. For that, I'll create two scripts. First create script called Meal Fighter. Then I'll create a script called Combat Controller. Okay, let me explain why I added two scripts here. The reason for that is because we want to build a combat system in a modular way. Because we want to reuse as much code as possible between the player and the enemy characters, right? Since both the player and the enemy has common actions like performing attacks, combos and all that, we want to reuse the code for doing that for the player and the enemy. Okay, So to achieve that what I'll do is I'll write all the common logic for the combat system inside the medi fighter script. The code for performing the attack and enabling the sword collider, performing combos. All those will be inside the Medi Fighter. The Medi Fighter script will be used for both the player and the enemy. Okay, this will have a code for performing the attack, but it won't have the code to determine when the attack should be performed. Okay, the code for that will be different for the player and the enemy. In the case of the player, the attack should be done when the user press an input, right? But in the case of the enemy, it's not controlled by the user's input, right? It's controlled by the AI of the enemy. Splitting our code into different components like this will allow us to reuse our code instead of fighting the same code for different objects. I'll right. That's one of the main principles of the clean coding practices. It's, do not repeat yourself, which means we should not have any duplicate code in our project. We should try to reuse as much as code as we can because it'll allow us to easily make changes to our code in the future. Okay, let's start by implementing the merely fight descript. Here I'll create a public function called try to attack. All right, so this function will try to perform an attack if the character is not already performing an attack or if the character is not performing any other actions. Okay, so first singular variable to keep track of if the player is in an action or not. So here I'll create a bulling variable called inaction. And I'll say it defaults by default, okay, from the try to attack function if the player is not already performing an action. Then we can go ahead and perform the attack. Right? To perform the attack, we just have to play this animation from our animator. First, we need to get a reference to the animator from the Lei Fighter crap reference from the apague function. All right, now we have to play this animation. And we have to play it by using its name. Right? I want to play this animation by using its name. When we build attacks and combos, the user just has to provide the name and we'll use that name to play the animation. Okay, play an animation by its name. We can use two functions. We can either use the play function or we can use the cross fate function. In this case, I'm going to use the Crossphd function because it allows to slowly transition to the animation we want to play instead of playing it immediately. Okay, So in this function, first we have to pass the name of the animation we want to play. That is slash, right. Next we have to give the transition duration. So I'll just give a small value like 0.2 All right, 0.2 doesn't mean 0.2 seconds, because in the crossphate function we are actually passing the normalized transition duration, okay? Not the transition duration in seconds here. When we pass 0.2 it means that we'll take 20 percentage of the current animations time to transition to the animation. Okay. We also have another function called crossphate. In fixed time, this function takes the seconds for transitioning. In this case, when we pass 0.2 it'll take 0.2 seconds itself. But I like to use cross weight instead of cross weight and fixed time. Because if our current animation is a bit long, then it'll take a little more time for the transition. That works really nicely for most of the animations, all right? But when you use cross fate function, there's one thing you have to note if your current animation that's being played is too long. So for example, if your idle animation is really long, if it's like 10 seconds, then the transition will look really weird because it'll take a lot of time to transition. Okay, 20 percentage of 10 seconds is 2 seconds, right? 2 seconds will be really long for a transition to the attack animation, and it'll look really feared. Just keep that in mind. If you're using the cross state function, then your idle animation has to be a short one. In our case, our idle animation is just 1 second. That won't be a problem for us. Okay, calling this function, we'll play the attack animation. When we play the animation, we also have to sit in action to true to make sure that we can't perform another attack while this attack is being played. Once we complete playing the attack animation, we have to set the inaction back to false, okay? But how can we know when the attack animation will be complete? In the unities animator, there is no way to know when an animation will be complete. Here after this line, if we just set the inaction back to false, it won't wait until the animation is complete. It'll turn this immediately. Okay, we can't write like this. Instead what we'll have to do is we'll have to manually wait for the duration of the animation. Okay, if you look at the slash animation, this animation is 1.5 seconds long. What we can do is, after we play this animation, we can wait for 1.5 seconds. Then we can set the inaction back to false, okay? Whenever we want our code to wait for a period of time, we'll have to put our code in a special type of function called cotine. Corotine is a special type of function with Nuberator as its return type. All right, here I'll create a corotine function called attack. We'll run these two lines from inside our cotine. Okay, so if you have no idea what corotineus, you can go ahead and read documentation. But basically corotin is something that you use when we want to make our code wait for some time. Or when you want to execute our code over a period of time. Okay, So you can go ahead and read more if you want. In our case, after playing the animation, we want to wait for the length of the animation before setting the inaction back to Ford's right. So to make the code wait for a few seconds, we have a function called wait 4 seconds. Okay, So this is actually a class, not just a function. That's the reason why we have the new cured at start. All right, in the parameter of this, we can pass the seconds for which we want to wait. Let's say if you want to wait for 1 second, we can pass one over here. But in our case, our animation is 1.5 seconds here. We can just pass 1.5 seconds. All right, obviously we don't want to hard code this value because slash is not the only attack that we'll have. We'll have multiple attack animations, right? We have to programmatically find the length of the animation. We'll be doing that soon. But first, let me show you how to make a code. This is a function for making a code to actually make this function. Before going to the next line, we have to use the yield Return keyboard in front of the function, okay? So now we'll wait for 1.5 seconds from here before going to the next line. All right, so after waiting for the length of the animation, we can just set the inaction variable back to faults, okay? Now, the inaction will only be set to false once we complete playing the slash animation, okay? But we don't want to hard code this value over here. We want to find the length of the slash animation programmatically, right? For that what we can do is we can get the state of the animation that is currently being played. From that we can get the length of the animation. Okay, So if you type animated, do get state here we have two functions. Get current animated state info and get next animator state info. Next animated state info function is the one we want to use. Okay? The reason for that is because when we call the cross fate function, we know that it won't play the slash animation immediately, right? Instead, it'll slowly transition to the slash animation from our current animation. When this line is executed, our animator will be in a transition state. In the transition state, the current animation will be our locomotion animation. The next animation will be the attack animation, right? That's the reason why we are using the get next animator statement for. Okay, and here we have to pass the index of our layer. If you look at our animator, the attack animation is in the second layer. And since you want to pass the index, the index will be one, okay? The index, first one will be zero and the second one will be one. Just like an array, I'll pass one for the index. I'll just show this inevitable, called an state, okay? And from the anim state we can get the length of the animation. Now we are programmatically finding the length of the animation and we'll wait for it to complete before setting the inaction to faults. Okay? We also have small issue with the screen. We call the cross fate function Un won't start the transition to the new animation immediately. It'll only started after the current frame. Okay. We have to wait for one frame before we call the get animated state function. Otherwise we'll get the incorrect state because the transition has not yet started. Okay, so we have to wait for one frame after running the cross weight function. Fortunately, there's an easy way to wait for one frame. We just have to write shield return. No. Okay, What this will do is this will make our corotine wait for a single frame. All right, this is all you have to do to perform the attack animation. Now from here we can call the attack corotine And perform the attack animation if the player is not already in an action. Since the attack is corotine, we can't just call it like we call any other function. Instead we have to put it inside a special function called start cotine. Okay? So this is how you call a corotin from a normal function. All right, So this is all you have to do from our merely fight descript for performing the attack. Next we should actually call the strike to attack function when the user presses an input, right? That code can't be written inside the male fighter script because that code is specific to the player, right? In the case of enemy, the condition for performing the attack is different. What we'll do is we'll write that code in the combat control script. Okay, from here first you need to catch the reference to the male fighter. I'll do that from the awake function. Okay, and then from the update, if the attack input is pressed. So I'll call the kit buttoned down function and I'll check for the attack input. The attack input is not defined by default, We'll have to define it manually. I'll open up the input manager from the project settings. Here we have lots of inputs, but we don't have one that's named attack. But if you look at the Fire one input, it uses the left mouse button and the left control button. We can use this one for the attack, we can just rename it to attack and use that. All right, so back in our code if the attack button is pressed, then we have to call male fighter, tried to attack function. Okay, this function will perform the attack if we are not already in an action. This will make sure that we won't perform the attack multiple times when we spam the attack input. All right, yeah, this is all we have to do to perform the attack, to score humanity and attach these two new scripts to our player. Okay, I'll attach both the male fighter and the combat controller. Now if you test the game, if I press the left mouse button or the left control button, you can see that the player is attacking. Okay, so this is actually a swath animation, But we don't have a sword yet, we'll be adding that soon. But let's implement the attack properly. This works, but we still have to fix a few problems. The problem is we can move by the attacking. Okay? We shouldn't be able to do that, right? We can fix that issue by not allowing our player controller script to move the player while the mele fighter is in an action. Okay, we can just check the value of this variable from the player controller script. If it's true then we can prevent the code for the movement. Okay, we could just make this variable public and access it from the player control script. But it's not a good practice in object oriented programming to create public variables. The reason is because if we make it public, we'll also be able to set its value from other classes, right? But we don't want that the value of inaction to really be set from the Lei Fighter. What we can do is we can just make this a property instead of making it a variable. To do that, we can add a getter and a setter. All right, so this is our property with a getter and setter. But we should only be able to set this from the current class, right? We should not be able to change its value from outside. What we can do is we can make our setter private, like this. All right, now our inaction is actually a property. And by the way, according to the naming conventions in sharp the properties has to start with a upper case letter, okay? So we have to make an upper case. So we can just rename this property by right licking on it and selecting, rename by the way, you can also use the control R, short cut, okay? And I'll make the upper case, that will automatically change the name in all the places where we use that property, okay? Now, since the inaction is a property, we'll be able to access its value from the player control script. Okay, from here first we have to get the reference to the Mealy Fighter. I'll go ahead and do that. All right, let me catch the reference from the awake, then from the start of the update function. I'll check if Mele Fighter taught in action is true. If that's true I'll just return and I want to execute any of the code below. Okay, this will make sure that we can't move when we are performing an attack. Let's continuity and test now. Now, even if I hold the moment input while attacking, the player won't move. She move once the attack is over. Okay, another issue that we have to fix here is if we attack while holding the moment input, it won't move. But soon after the attack is over, it'll go back to playing the running animation even if the moment input is not pressed. Okay? So that is happening because the more amount parameter of the animator is not zero. When we were starting the attack, right? Once the attack is over, we'll play the running animation for a short time before setting the more amount back to zero. We can easily fix that by resetting the more amount to zero while inaction is t here. Let me just add braces because we have multiple lines in the F from here. We can just set the more amount variable to zero if we are in an action. All right, now if it, we shouldn't have that issue. Okay, so the attack is working properly. All right, next we should add a sword to the player's hand because they're playing a swath animation. So we'll be doing that in the next video. 11. Reacting to Attacks: Here in this video, we'll add a sword to the player's hand. We'll also add an enemy character and we'll make him play this hit reaction animation when he's hit by the player's sword. Let's implement this first. Let's add a sword to the player's hand. I'll go to the Unities Asset store. I'll find a sword asset that we can use. Let me just search for a long sword over here. Okay, And this is a sort you want to use. It's a free asset. Just click on it. And since I've already added this asset to my account, I'll have this open in Unity button. But if you open this for the first time, you'll have to add this asset to your account. After that, you'll be able to open it in Unity. Okay, Click on Open Unity Editor. This will open that asset in Unity's Package Manager. All right, it's taking some time to load, okay? Not open the asset from the package manager, but we can see the asset over here. If you can't see it, just search for long swat and you'll get it, okay. Now after selecting the asset, we can just click on the Import button to import it into our project. Okay, go ahead and click Import, and this will import it into our project. All right, the sword will be in this folder here on the prefabs, we'll have a long swatter. Okay? But the Swat has a weird pink color. Whenever you see this color in Unity, it means that Unity is not able to recognize the shader. Okay? So if you look at the long Swat model, you can see that its material is also pink because it uses a standard shader. Okay, and since you're using the universal render pipeline, it won't be able to render standard shaders. So we'll have to convert the shader into a universal render pipeline shader. All right, let's find this material in our project files. For that, we can click over here and click on Select Material. Okay, there are two materials for the Swat. We have to convert both of these to use the UR pat. That's pretty simple. We just start to select these two materials and click on Edit under Pipeline, Universal under Pipeline. Click Upgrade Selected Materials to Universal under Pipeline Materials. Okay, this will convert the material to use the Universal under Pipeline shader. Now we can see the materials on the sword. The sword is not pink anymore. Okay, let's add the sword to the hand of the player. By the way, there are two game objects here. There's a parent game object and there's one for the mesh, we only need a single game object. We can just copy this one and paste it over here. And then you can just delete the prefab. Okay, now let's place this swat into the player's hand first. Tell rotated in the x axis by around 90 degrees. I'll just type in 90 over here to rotate it perfectly. Okay, let's move this and place it into the player's hand. We can actually use the front view. Just click on the Z gizmo and then click on the center to make it orthographic. Okay, and if I just swum in, now we can see the player and the Swat in the front view. From here we can easily place it into the player's hand. Okay, now let me switch to the side view by clicking on the Xchismo. All right, let me just make sure that the Swat is in the player's hand. Yeah, this looks fine to me, so I'll click on the center to change it to the perspective view. Let me just make sure that this is placed perfectly. That looks fine, but I think the size of the sort is a bit big right now. We can actually go ahead and reduce its scale if you click on the Sort from here we can find its mesh. This will give us the FPx file from the model tab of the PX file. We can reduce the scale factor a bit. I'll change it to 0.9 to reduce it a bit. Okay, so yeah, that should be enough. Now, if you look at the sword, you can see that the colliders don't fit perfectly because we change the scale factor of the model. We can fix that by removing these colliders and adding them again. Let me just minimize the material. Let me go ahead and add a new boxlider to it. Okay, we don't want the box collider to be this fed. Let me go ahead and reduce the excise. Okay, that should be enough. We only need one collider for the sword, we don't need another one for the handle over here. Okay, Next I'll also turn on the trigger check box of the box collider. Because we want the sword to be a trigger, we don't want it to really collide with other game objects and act as a physics body turning on trigger, we'll make sure that this collider will only be used for triggering events and it'll be ignored by the physics engine. Okay, so next, even though we have positioned the sword in the player's hand, the sword won't move when the player's hand move, right? So to make it move along with the player's hand, we have to make the sword a child of the player's hand. Right? If we expand our model inside the hips, we have spine. Let's keep expanding until we find the right hand. Here we are, right shoulder, right arm, right forearm. And finally we have the right hand. Okay, we want to make the sword a child object of the right hand. So let me just drag and drop the sword onto the right hand object to make it a child. And by the way, I'll just name this sword as long sword instead of long, short mesh. I like that better. Okay, so now the sword should move along with the player's right hand. So let's try testing it. Okay, the sword is moving the player's right hand, but we have a problem, since the player's hand are pretty close to her body. The sword is going through her legs. Right? So let's go to the scene view to take a better look at it. Okay, Yeah, if I woman, you can see that the hand is like freely close to the body. It's actually a bit inside her leg. The sword is also going to pass through the leg. Okay, so this is actually a problem with the animation fixes. We'll have to find a better idle animation. Or we'll have to modify this animation somehow. Maxima has a really cool feature that will allow us to chain the character's arm position in an animation. So let me go ahead and show you the cat character selected. I'll search for idle animation. Okay, this was the idle animation we were using, right? In this animation, you can see that the hands are pretty close to the leg. But we have a slider in Maxima over here called character arm space. If we increase it, you can see that it's the hands away from the body. This increases to something like 70. All right, so that should be nuporous. Let's go ahead and download this animation. Okay, and once it's downloaded, we can go ahead and switch the current idle animation with the new one that we just download it. Okay, so I'll just lead the old idle animation and I'll import the new one that we just downloaded. Okay, so we have to rig this animation first. So let me go ahead and do that. If we just drag of the player, we should be able to preview it. Okay, just to be safe, let's also change all the base upon to original and check pak interpose for all the road transforms just to be safe. And make sure that we don't have any root motion in the animation. Okay, now we go to the animator inside of our locomotion, Bluntre. You can see that the first animation is missing because we deleted it. Let's go ahead and assign our new ideal animation here. Now things should work like before, but with our new animation that has wider arm space. All right, so you can see that the idle animation looks a lot better when the arms are placed away from the body. Okay, yeah, you can see that the sword is moving along the player's hand. If I perform the attack now the attack animation looks a lot better with the sword in the player's hand right. Next, let's bring enemy characters to our game and make the enemy play a hit animation when we swing the sword. All right, again, I'll go to Maximo to find an enemy character. All right, under characters I'll search for Paladin. There are also other characters in this style. If you want to use them, just go through them and use the one that you like. You don't have to use the same one as me. Here we have two models. One of them comes with props like the sword and the shield. I'll just double the one with the props. We might want to use the sword in the future. Okay, so let me go ahead and download it. So yeah, when downloading a character, make sure to download it in Depots. Okay, I have already downloaded this character to save time, so let me go ahead and import the character to Unity. So we'll import it to the Models folder. Okay, so this is the character. It doesn't have textures right now, but we can score the material stab and click on Extract textures. And I'll actually put this in a separate folder and I'll call this Pella then textures just so that it defined the textures in case we want to modify them in the future. Okay, now it's prompting me to fix the novel maps, so I'll just fix our enemy character has textures now. All right, next we have to rigging the animation type to humanoid. Since this is a character we have to use to create from this model, for the other definition. And hit apply. Okay, so the character should be rigged. Now let's look at the character. It has an animator attached to it. Here we can assign the same animator controller that we use for our player, make it play the idle animation. Let's try testing it now. Okay, so yeah, I can see that this character comes with a sword and a shield. But right now it doesn't do anything when we play our attack animation. So we have to add a collider on the enemy character and we have to detect the collision between the players sword and the enemy's collider. Okay. Let me go ahead and add a capsule collider to our enemy. All right, I'll change the height to something like 1.8 because that's the average height of a human to places in the center. I'll set the y of the center to the half of 1.8 which is 0.9 okay? So the radius is big right now, so let me reduce it something like 0.3 okay? I'll actually relate this character to something simple like enemy. And we can even unpack the prefab just so that we can create our own prefabs in the future. Okay, now the enemy character has a collider. We have to detect the collision between the players sword and the enemy's collider. When handling collisions, we have to make sure that the players sword can affect the enemy's collider. Similarly, on the enemy sword can affect the player's collider. Right? It'll look really weird. If the player swings the sword, the player itself plays animation because a part of the players sword went through the player's body during the attack animation. Right. To make sure that doesn't happen, what I'll do is I'll add multiple layers first and then one for the enemy. Then I add a layer called Player Hit Box. This will be the layer in which the player's sword will be assigned. Then I'll create a hit box layer for the enemy also. Okay, so the player is going to be in the player layer. And we don't have to change all the children, just this game object. So this object only then the layer of the enemy is going to be enemy again. I'll say no. And then we'll put the players sword in the player hit box layer. Okay. And the enemy sword should be in the enemy hit box layer. But the implementation of enemy attacks would be done later so we don't have to assign it now. All right, so with all these objects assigned to separate layers, what we can do is we can tell Unity that the player hit box surely collide with the enemy layer. Okay, if click on Edit and go to Project Settings. Here under the Physics tab, we have a Layer collision metrics. This letter specify what layers can collide with what other layers. In our case, we want the player hit box layer to collide with the enemy. So we can cancel everything else except for the enemy. Okay? And similarly, the enemy hit box should collide with the player layer. Okay, So let's turn off everything else using layers like this and making sure that they can only collide with one other layer. It's also good for making a game more efficient. If you do this, then you phone detect any unwanted collisions and trigger random events. For that, it's always good to use the collision metrics and reduce the number of collisions and make a game more efficient. Okay. By the way, one thing I forgot to mention is that for two game objects to collide, at least one of the game object should have a rigid body component. Okay? Otherwise collision won't happen in Unity. What we can do is we can add rigid body component to our long sword. All right, I'll just make it kinematic so that it won't be affected by external forces. And I'll also turn off gravity. Okay, so now we have everything for detecting collisions. So let's actually write the code for detecting collisions. Now when a trigger like the player Swat enters the enemies collider, it'll call the on trigger enter function on all the scripts that are attached to the enemy character. All right, so what we'll do is we'll write the code for detecting the sword collision and playing the hit reaction and all that in the made fighter script. Okay, both the player and enemy needs to have this functionality. Writing it in the Meli Fighter is the way to go. We also have to make should attach the Meli Fighter script to the enemy because the enemy should also be able to fight in our combat system. Right now in the fighters script, I'll just type on trigger. Here we can see we have a function called on trigger enter. If a presenter, it'll automatically create the trigger enter function for us. If this function is called, then that means trigger entered the characters collider right from here. It'll be good if we verify if the trigger that entered the characters collider is actually a weapon. We can do that by checking the tag of the other collider. Check if other tag equal to equal to hit box. Before we forget, we have to assign this tag for all our weapons. Okay, so let me go ahead and assign it for the long sword. So these are all the predefined tags that we have in Unity. So we have to create a new one. I'll call this one hit box, and I'll assign that as the tag of the long sword. Okay, so now back in our script, if the other collider that entered the characters collider is a hit box, then we should go ahead and play the hit animation. But we don't have a hit reaction animation right now. Then we should go ahead and play the hit reaction animation, But we don't have that animation right now. Now just for testing, we can just write a debut log statement. I'll just say something like character was hit. Okay, so now if we won the game, if we go near the enemy and play the attack animation, you can see that in the console, it prints the character was hit. Okay, next we have to find a hit reaction animation. And we have to play that animation when a sword enters the character's glider. Okay, again, to find the hit reaction animation, I'll go to Miximo.com I'll make sure to select the Erica Cher character before selecting the animation because I want all my animations to be rigged by using the Erica Cher character. You can also use other characters like the Paladin that we just downloaded. The reason why I like using same character for everything is because I won't have any confusions. I can rig everything by using the same Aaa. All right, I'll just switch back to the cache character under the animations. I'll search for Swat impact here, we have a few Swat impact animations. This is the one I want to use. Okay, so go ahead and download it. I have already done that, so let's go ahead and import it into Unity. Okay, let me drag and wrap it into Unity. Let me just make this zoom out so that I can see the name clearly. This is a new animation. So first we have to go ahead and rig it. I'll select Humanoid, and copy from Avada. And select Avada, since that was the one we used while downloading the animation from Maximo. Okay, next in the animation step, I'll change everything to original and I'll select baking to pose for the rotation and transform y just to make sure that we don't have any root transform in those axis. I don't mind if there's some root motion in the exit axis because that's fine for an attack animation. Okay, so let me click the apply button and let me see how the animation looks. So yeah, that looks fine. So next we need to add this into our animator. I'll go to the our right layer and I'll add the animation over here. I'll just rename it to something more shorter, like sort, impact. Okay, after playing the impact animation, we have to go back to the empty state. So let me create a transition back to the empty state. Next we have to play this animation when the sword enters a characters crider. So let's go back to the mele fight descript. From here we have to play the Swat impact animation. While we play the animation, we also have to make sure that the animation won't be interrupted by anything else like another attack or something that we have to use, the same technique that we used for the attack. We have to set the inaction. We should really set it to false once the animation is over. What I'll do is I'll just copy the attack function. I'll rename it to Hit Reaction. And I'll change the animation to Sward Impact. Okay, so this will play the Sward impact animation and wait until it is complete. Now from here, we can go ahead and call the play hit reaction. By the way, we should really do this if the player is not already in another action. Right here, I can add another condition and check if the player is not already in another action. By the way, I keep saying player, but when I'm writing some code in Le Fighter, it applies to both the player and the enemy characters. All right, let's go to and T and see if the hit reaction animation is working. All right, so if I go near the enemy character and try attacking, you can see that the enemy is playing the hit reaction when we attack. But we'll have a problem here. The enemy will not only play the hit reaction animation when we attack, but he played whenever the sword enters his collider. Okay, so in this case you can see that I'm not attacking the enemy. But he's still playing the hit animation because the player sword entered his collider. Okay, so that is one thing we need to fix and we'll be fixing that in the next video. Yeah, thanks a lot of watching and I'll see you in the next video. 12. Attack States: N in the previous video, we made the enemy play a hit reaction when the players sword enters the enemy's collider. Now the enemy plays the hit reaction while the attack, but the problem is the enemy will play the hit reaction even while we are not attacking. If we just point the sword into the enemy's collider, even then the enemy will play the hit reaction. Right fixes, what we can do is we can make sure that the player's sword is only enabled for a short period of time while the attack is being performed. All right, to achieve this, what I'll do is I'll split the attack into three different states. Wind up, impact, and cool down. Wind up is the preparation of the attack. Impact is a part where the player swings a sword. And finally, cool down is a part where the player brings back the sword after the attack. Once we split the attack into three states like this, we can make sure that the collider of the sword is only enabled during the impact state. Okay, that will allow us to solve our issue. Splitting the attack into three different states like this also have lots of other benefits. It'll allow us to easily implement things like combos, counterattacks, and all that. Let's start implementing it in the Madi Fighter script. We need to split this attack into three parts, right? Do that. What I'll do is I'll define enum called attack state. I'll define three, um, states here, wind up impact and cool down. Okay, at the start I'll also add another state called idle which indicates that we are not performing an attack. All right, then I'll define avatable of type attack state. Now when we perform the attack, we have to change the state of the attack based on the time of the animation. Okay, so if we look at our animation, let me just double look at, okay, let me just make it a little big. Yeah, if you look at our animation up to this part, it's actually the wind up right up to 33 percentage. It's wind up from there to here. It's the impact part. And finally the rest is the cool down, right? The impact happens between 33 percentage and 54 percentage, right? We can use this time of the animation to determine which state we are in. What I'll do is I'll create two flow variables called impact start time. Impact Time. The impact start time is 33 percentage, right? I'll set its value as 0.33 because we'll get the normalized time of the attack 0-1 okay? And impact end time is 55 percentage at 0.55 By the way, I'm just hard coding this value right now. In the future, we'll create scriptable objects to store all the data of the attacks. But I'll just hardcode this for now to make the implementation PC. At the start of the attack, the attack state will be in wind up, right? Then when the time of the attack reaches above 33 percentage, then we have to change the attack state to impact. We have to enable the collider of the sword. What we can do is what we are waiting for the animation to complete. We can create a variable to keep track of the time. If the time goes above 33 percentage, then we can switch the state to impact. But the problem is we can't keep track of the time and switch the state and all that if we are waiting like this. Okay, if you're waiting using this function, then we won't be able to do anything else badly. What I'll do is I'll wait for the animation to complete one framed time by using a while loop. Here I'll create a variable called timer, and I'll set it to zero. By default, the timer is less than equal to the length of the animation. We'll wait for one frame. Okay? And we also have to increment the timer each frame. I'll increment it by time la, time. All right, so what this will do is until the value of the timer becomes greater than the length, we'll keep waiting for one frame. Okay, So this piece of code will wait for the entire length of animation, just like this function does. But the thing is, if we wait using a wide loop like this, then we'll also be able to do other things while we're waiting. All right, I'll remove this line and I'll wait by using a wide loop. Okay? Now from here if we are in the wind up state and if our timer becomes greater than 33 percentage, then we have to switch from the wind up state to the impact state, right? If the current attack state is wind up, if the value of the timer is greater than 33 percentage, how can you check that? We can't simply check if timer is greater than impact start time tried because this is a percentage of the attack, not the actual time. We have to find the normalized time by dividing the timer with the length of the animation. Okay, here I'll create a variable called normalized time. It'll be the value of the timer divided by the length of the animation. Okay, and from here we can check if the normalized time is greater than the impact start time. I think we can check greater than equal to because we should start to ching and it's directory positage. Okay, if this condition is true, then we can change the attack state to impact here. We can also enable the sort collider. All right, so we'll be doing that later. First, let's handle all the state changes. So next, if you are in the impact state and if the time goes about the impact end time, then we have to change from the impact state to the cool down state. Right from here I'll check if the normalized time is greater than equal to impact end time. In that case I'll change the attack state to cool down. And from here we should also disable a collida. Okay? And finally, I'll also write in all safe condition for our cool down state. Okay? But right now from the cool down state we don't have to do anything. But in the future we can handle things like combos from the cool down state. All right, finally, once we out this wild loop, and we have finished waiting for the animation to complete, we can change the attack state back to idol, which means we are not performing an attack. All right, so now we have split our attack into three different states. I'm not just doing this for enabling and disabling the colliders. We could have done that with much lesser code. But splitting our attacks into different states like this will be really handy in the future when we implement other features like combos and counterattacks and all that. Okay, next we have to enable the collider when we start the impact state, and we have to disable it at the end of the impact state. For that. First I'll get a reference to the sword. All right, let me also create a variable to store the collider of the sword. All right, and then from the start function, if the sword is actually assigned, then I'll get the collider of the sword by using the get component function. Okay? And also by default the Swartz Collider should be disabled, right? So go ahead and disable it. All right, now when we start the impact state, we can enable a sort collider. Then we can go ahead and disable it at the end of the impact state. All right, this is all we have to do now. The sort surely be enabled during the impact state. Just for seeing how this works, we can go ahead and make our attack state public so that will be visible in the inspector. Let's go to your D and tests before we have to assign the Swat collider to the script. Let me go ahead and do that. Okay, now let's start testing this. All right, now if you run into the enemy with a sword, you can see that the enemy is not playing the hit animation. But if we attack, the enemy is playing the hit reaction. Because during the impact state of the attack, the swords collider will be enabled. All right, we can actually minimize a game window and look at the attack state in the inspector to see what's happening. By default, it's in the idle state. And when we start attacking, it'll go through, wind up, impact, cool down, and then return back to idle. Okay, we have fixed that issue. We have split our attack into three states in the code. I'll make the attack state private again because it's not good to make it public, because its value can be changed from other classes. All right, I'll start the video here. Thanks a lot for watching and I'll see you in the next video. 13. Combos & Architecting Attacks as Scriptable Objects: Hay phone. In this video, we'll architect attacks using scriptable objects. And we'll also look at how to add multiple attacks and make the player perform combos. Let's get started right now. In our code for a performing attack, everything is hard coded, right? Things like animation, name of the attack, and the impact start, time and time. All those things are hard coded. We don't want to do that because slash is not the only attack we are going to have. We want different characters to have different set of attacks, right? We want to design our combat system in such a way that a designer can add and edit the list of attacks of a character without touching the code. All right, to achieve that, we'll be using scriptable object. Unity. Scriptable object is just a data container that can be used to store large amounts of data. It's really useful when we want to make our game designer friendly by separating the data from the code. It also has other benefits like reducing the memory usage of the project. This is what we're going to use to architect our attacks. So let's open up our project. First, I'll create a new script called attack data. Okay, so this is going to be the scriptable object class that'll store all the data of an attack for this class. Instead of inheriting from mono behavior, I'll inherit from scriptable object. Okay, here we have to define out the data of the attack, like the animation name, impact, start and time, et cetera. First, let me create a citilized field for the animation name. All right, I'll just call it anim name. Then we'll also have to expose it by creating a property, right? This is how we usually do it. But to make the shorter, what we can do is we can create the property in a single line like this. All right? But the problem is this won't be serialized simply by using the serialized field attribute. Okay? But if we add a field at the start of the attribute, then it will also serialize properties. Okay? Defining it like this is much shorter than creating a private variable and then exposing it using a property I'll just cuts next. I'll also create properties for the impact start time and impact gen time. Okay, this will be our scriptable object class. Next to create instances of the attack data scriptable object, we have to add an attribute on top of this class. We have to add this attribute called create Acid menu. Here we have to pass the menu name parameter. This will be the menu that appears when we write click in the project window. Here I'll give something like combat system, create a nu attack. But I'll just make these two properties start with an upper case letter. Because according to the naming conventions of properties, the first letter should be upper case. All right, now if we go to Unity and click on our Project window, under the Create menu, we have a new menu called Combat System. Inside that we have to create a new attack. Clicking on this will create an instance of our attack data scriptable object. Okay, here we have fields like the animation name, impact, start time, and impact in time. This is how we are going to create all our attacks. Okay, I like to put all my attacks in the game folder because it's something that can be created by game designers. I'll just leave the attack that we just created under the Games folder. I'll create another folder called Attacks. This is where I will create all our attacks. Okay, so let me go ahead and create our slash attack, create a new attack and Mate the animation name is also because that's what we gave in the animated control. All right, let's look up the impact start time and time in the code. The impact start time is 0.33 and the impact end time is 0.55 Right, let me enter those values here. All right, now from our merely Fighters script, we have to use this instance of the scriptable object instead of hard coding the values here. Right, So let me just remove these two variables. Over here, I'll define a list of attacks. Okay? So it'll be a list of the attack data, scriptable object, and call it attacks. The reason why I'm making it list over here is because each character will have a list of attacks that he can perform as a combo. Right? We'll be implementing combo soon. All right, here we have to get the animation name of the attack from our attacks list. Since we haven't implemented combos yet, I'll just take the first attack from the list. I'll pass the animation name to the crossw function. Okay, next we have to do the same for the impact start time and time. So I'll just take the impact start time property of the first attack on the list and I'll do the same for the impact time also. Okay, so now back in Unity in the mainly fighter script of the player, we'll have a list of attacks. Here we have to add our attack. Now if you play the game, everything should work as usual. But now we are taking the data of the attack from the scripted logic instead of hardcoding it in the code. Next, let's add more attacks like this and implement combos. I'll go to mix and download two other animations. The first one I'll download is this outward slash rap search for outward under animations and you'll find this animation. Okay. The next one I want to use is this Sparta. Again, just search for Sparta under the animations and you'll find this. Go ahead and download these two animations. I have already downloaded it. Let me go ahead and import it into my Unity project. I'll write these two other new animations outward and kick. So first we have trick them. Let me change the animation type. Humanoid select, let me just trick them. Now we should be able to preview the animation. All right, for this animation, I don't want the entire animation because the first few frames, in the first few frames, the player doesn't do much. If we take the entire animation, a combo will look really slow. I'll just go ahead and start this frame, frame number 14. To do that I can just drag this from the start and place it at frame 14. Okay, so now the animation is much shorter. Next, I'll change the based upon to original for all root transforms and I'll also bake, interpose the rotation and transform y to remove any root motions. Okay, let me go ahead and interply. This is what animation looks like. Okay, so next let's look at our kick animation. For this one we can use the entire animation but we have to remove any rote motion. I'll change the based upon original for all the rot transforms. I'll back into post the transformation and trans position. All right, so now we can go ahead and add this into our animator. Okay, and let me change their names to something more simple. So for the outward I'll just name it something like horizontal. I'll name the kick as Sparta kick. Then we also have to make a transition back to the empty state, because after playing these attacks, we have to go back to the empty state and keep playing whatever animation we are playing in the base layer. All right, next let's go ahead and define the attacks for these under attacks, I'll go ahead and create a new attack. First I'll create the horizontal attack, so let me enter its animation name. And we also have to find the impact start time and end time. Right? If you look at the animation, we can start the impact somewhere around here, around 1920 percentage of the animation. And then we can end it around 36 percentage. Okay, back in our attack, impact start time will be 0.20 for 20 percentage, the end time will be 0.36 All right, next let's create the Sparta kick attack. The animation name is Sparta kick itself. Then we have to find the impact start time and time. Let's look at the Sparta animation. All right, for this animation, we can start the impact somewhere around here, 36, 37 percentage. Then we can end it when the player starts to pull back his feet, right? So the starting time as 36 percentage, 0.36 and the ending time as 0.56 All right. By the way, one thing to note is that in case of the Sparta kick, we should not be checking for collisions between the players Swat and the enemy's body. We should be for collision between the foot of the player and the enemy's body. We'll be setting up colliders on the foot and hands of the player soon. I just want to let you know in case if you're wondering how that would work. Okay, now we have our three attacks, so we can go ahead and assign them in the attacks list of our Le fighter. Okay, I'll just make horizontal our second attack, and Sparta our third attack. All right, and then in our Le Fightercript, we should write the code for performing combos using our three attacks. Okay, perform combo. What we can do is if the tried to attack function is called while the player is already in an attack, then we can go ahead and call the attack function again and play the next attack in our attacks list, right? So the first thing we have to do is we have to check if tri attack is called while we are already in an attack, right? I only want to perform the combo if the current attack that's being performed is past the impact state. Okay, I don't want to perform the combo. If try to attack is called when the current attack is in the wind up state, that would be too soon to register a combo input. Okay, so what I'll do is if the tried to attack function is called and if we are performing an action, and if the attack state is impacted, cooled down, then we have to perform the combo. Okay, this should be double equal to, that's why we have the error. All right, if the attack state is impact, cool down, then we should perform the combo once the current attack reaches the cool down state. Right, so what I'll do is I'll create available called combo. I'll also create an integer variable to keep track of the current combo count. Here I'll create an integer variable called combo count. And I'll set it to zero by default. Then if you try to attack is called while we are in the impact of cool down state of an attack, then I'll set combo. Okay, Once you reach the cool down state, if combo variable set to true, that means we have to perform a combo right from here. First of all, we set the value of two combo defaults. Then we can go ahead and increment the combo count. But when we increment, we also have to make sure that the combo count doesn't go beyond the length of the attack. We have to check if combo count is created equal to the count of the attacks, then we have to reset it back to zero and cycle through the attacks again. Right, There's actually a simple way of writing this. We can just say compo count is equal to compo count plus one mod I have to put this in a bracket, and then I have to mark this by the length of our attacks. Okay, so this line is same as writing these three lines. What it'll do is if the compo count becomes equal to the count of the attacks, then the result of the modulus will be zero. It's one of the basic operators that you learn while learning a programming language. I'm not going to spend a lot of time explaining how it works. You can just look it up if you're not sure how it works. This land will increase the compo count in our attack function. Instead of always using the zero attack, we have to use the attack at the compo count index, right? So let me also change that for the impact start time and impact end time. All right, back in here. After incrementing the compo count, we have to go ahead and call the attack corotin once again. And perform the next attack. From here, I'll go ahead and call the attack corotine. This will perform the next attack in our attacks list. Okay, After that, I just want to exit out of this co routine because I don't want to execute these two lines where we're setting the attack state title and inaction defaults because we are still performing another attack, right? We should not come down and execute these lines. We want to stop the corotine from here. To stop a corotine and exit out of it, we can use B. Okay, so this will make the exit out of the current corotine while executing the next attack in our attacks list. Right, If we don't perform a combo, then this line won't be executed and we'll reach the end of that attack, corotine, where all these variables will be increased. Okay, so from here we also have to reset our combo count. Because the next time we start an attack, we want to start from the beginning. All right, this is all we have to do to perform a combo. Let's go to Unity and see if it's working. All right, if I keep pressing the attack input, you can see that we are performing a combo. All right. And we can also try performing the combo in front of our enemy. For the second attack, the enemy did not play the hit reaction, right? This is because the second attack happens really fast, and while the second attack is being performed, the enemy hasn't fully completed his hit reaction from the first attack. Okay, if we look at our core, we only play the hit reaction again if we are not currently in another action. Right? To improve this, what we can do is we don't have to wait for the entire length of the hit reaction animation. The reason is because if you look at the transition of the impact animation, you can see that we'll start transitioning back to the empty state around this point of the animation, right? If you open the settings, it's around 0.65, 65 percentage of the impact animation. We don't have to wait for the entire impact animation. We can set the inaction back to falls somewhere around this point. Okay, Since we're going to have different hit reactions in the future, what I'll do is I'll just wait for 80 percentage of the length of the animation instead of waiting for the entire impact animation. Okay, so wait for 80 percentage length. I'll just start to multiply the length of 0.8 Now if we go ahead and test the game again. Should play the reaction during the second hit. Okay, Now the enemy is also playing reaction during the second hit. Also, the second attack is really fast. If you want, you can slow down a bit from the animator. Here you can set the speed of the animation if you want. You can slow down a bit by changing it to 0.9 or 0.8 But I guess it's not that bad. Since I'm just building this for a course. I won't spend a lot of time on polishing stuff, but you can spend a lot of time on this and find the perfect values to make your combos look good. Okay, so the next thing I want to show you is that right now when we perform the combo, you can see that the enemy did not play the hit reaction for the final kick attack, right? The reason for that is because we're checking for the collision between the sword and the enemy's body, right? But for the kick attack, we should check for the collision between the player's fruit and the enemy's body. The interaction will sometimes work when we're doing it from the close range. Because in the close range the sword is also passing through the enemy's body. But if you do it from a long range like this, you can see that the enemy did not play the hit reaction. What we have to do is we have to add hit boxes on the foot and the hands of the player in case the player has any attacks like punching. And then we have to enable the colliders accordingly based on the attack. We'll be doing that in the next video. Thanks a lot for watching and I'll see you in the next video. 14. Different Attack Hitboxes: He. In this video, we'll add hit boxes to the hand and feet of the player. Then we'll enable the correct hit box during the attack, based on the type of the attack. For example, for the Spartachic attack, we'll enable the hit box on the right foot. Let's look at how to implement this. First, let's add collider to the hand and feet of the player. Let me just expand the bones. First I'll add a collider on the left foot of the player. Okay, so here I'll add a sphere clyder component. Right now the radius is pretty big, so we can reduce it to something smaller like 0.15 Okay, that should be good. Next I'll make the say, trigger because we don't want this collider to have physics. Then we also have to set its layer as player hit box because this is a hit box of the player. All right, we also have to set its tag as box. This will be the hit box on the player's foot. Let's also add this component in the right foot. Copy it from here. Let me expand and find the right foot. Okay, and I shall and paste our Spear Glider component. All right, here also we have to set the layer as player hit box. And we have to set the tag as hit box. Okay, next let's do the same for the hands of the player. So I'll just expand spine and first to add it to the right hand. Okay, so again we can just past the spear glider that we just copied. All right, here also we have to set the layer as player hit box and set the tag as hit box. Okay, let me also do the same for the left hand. All right, I'll paste the Spaclider. I'll also change the layer and the tag. Okay, so one thing to note is that for the collision to happen, at least one of the collider should have a fixed component like rigid body, right? That was the reason why we added a rigid body to our Swat object. But in the case of the player's hand and feet, I don't want to add rigid body to all of them. Instead what we can do is we can add a physics component to the enemy. The collision will work if either one of the collider has a physics component, right? We can add it to the enemy instead of adding to all the hand and foot of the player here. For the enemy, we can either add a rigid body or a character controller, both our physics components and they'll help us to trigger collisions. I'll just go ahead and add a character controller. Now since we have a character controller, we don't need a capsule collider anymore because the Character Controller comes with the collider. So I'll just go ahead and remove the capsule collider. We have to arrange the collider of the character controller properly. I'll just set the center to half the height. Okay, we can actually reduce the height to something like 1.8 Now the center will be 0.9 We can also reduce the radius. I'll just reduce it to something like 0.4 for the enemy. It's good to have a big collider because the player should not feel like he attacked and hit was not registered. Even if the collider is a bit big, that will work in favor of us during the game play. All right, so now we have hit box on the hand and feet of the player next. For each attack, we should be able to specify the hit box that we want to use. Okay, in the case of and slash for a swundle it'll be the sword, but for the Sparta kick, it'll be the right foot of the player. Okay, What we can do is in the attack data script, we can add num called attack hit box. Okay, so this can be left hand, right hand, left foot, right foot. Or the sword. Okay, In your game, if you have more weapons, you can also add a boxes for them. Next in the attack class, I'll create a property for the box to use. Okay, Now for each attack, we can specify the hit box to use the slash and slash horizontal. We'll use the sword, and the Sparta kick will use the right foot. All right, next from the minify descript. When we perform the attack, we should not simply enable the sword collider, but instead we should enable the right collider based on the hit box of the attack. First, we need to grab a reference to all the colliders we have. Let me create ap collider object for both hand and feet. Okay, so create the left hand collider and then the right hand collider. And similarly the left foot collider and the right foot collider. Okay, next from the start function, we have to grab the reference to all the glider. We can either make this a setilized field and assign the reference from the inspector, but since we are using a humanoid character, we don't have to do that. There's actually an easier way when we're using a humanoid character. We can get the bone of that character from the animator by calling animator get bone transform. Okay. And here we have to pass the bone that we want to get. Let's say I want to get the left hand bone. I just have to pass the left hand in the parameter. Okay, so this will give us the transform of the left hand of the player or the enemy based on the character to which this Mealy Fighter script is attached. Okay, from the left hand bone, we can get the sphere collider component. All right, we can store this in our left hand collider object. All right, next we can do the same for the right hand. In that case, we have to pass the right hand bone and I'll save it into the right hand collider. Okay, I made a mistake here. I saved it into the left foot collider instead of left hand. Let me change that. Okay, so now that's correct, and let me add Emmy Collins at the end. So next I'll do the same and get the collider for the left foot. So let me change these two left foot, okay, And finally, let me get the right foot collider. All right, so I'll change this to right foot. Okay, so once we get all the colliders, we have to disable them by default, right? We should really enable them when we are attacking. So let me go ahead and disable all the colliders. Okay, let me just copy and do the same for the foot colliders. All right, we can put the lines to disable the colliders in a function because we'll also have to disable all the colliders after the impact state of an attack is over, right? I'll just put it in a function called disable all colliders, Okay, I'll just call that function from here. All right, next, when we start the impact state, we should not simply enable the collider of the sword, but instead we should enable the collider based on the hat box of the attack. Right? For that what I'll do is over here I'll create another function called a. This function will take a reference to the attack because we can use it to determine which a box we have to enable. From here I'll just use a switch statement, just a crypt tip. We don't have to manually fill in all the cases of the switch statement. We can just write switch and hit the tab key twice. Okay, that'll create the syntax. From here we can just specify the variable we want to switch. In our case, we want to check the attack hit box to use enum right after writing that, if we press Enter key, it'll automatically fill in all the cases for us. Okay, now based on the value of the hit box to use, we can go ahead and enable different colliders. If the attack uses the left hand hit box, then we can go ahead and enable the left hand collider. Okay? And then if it uses the right hand, then we can go ahead and enable the right hand collider. Similarly, we can do the same for the left foot and right foot collider. Okay, And finally, if you sing a sword, we have to enable the sword collider. Okay, so now when we go to the impact state of an attack, we can go ahead and call the enable hit box function and we can pass the attack that we're performing right now. Okay? And then once impact state is over and we start the cool down state, we have to disable the correct collider, right? So in this case we can just disable all colliders and it'll just make sure to disable everything, okay? By the way, just rename this function to disable all boxes just to keep it consistent with enable hit box function, okay? Ls continuity and tests. When we perform this partakic the collider of the right foot should be enabled, right? What I'll do is once I play the game, I'll just minimize the game window. I'll select the right foot from the inspector so that we can see when the collider is enabled. Right now it's disabled, but when I perform the combo, you can see that during the kick attack, the collider of the right foot is being enabled. Okay, We can also try attacking the enemy and see if the enemy is playing the hit reaction during the kick. Yeah, enemy is playing the hit reaction. Yeah, that's working fine. Now since we have a way of specifying the hit box, we can also create other types of attacks, like punches and other kicks and all. If you want to use a different type of attack in your game, then go ahead and do that. Just specify the collider that you want to use and work. All right, so I'll stop the video here and I'll see you the next video. 15. Enemy AI: N. In this video we'll start the implementation of enemy AI. We'll be using state machine for implementing AI. And we'll separate different behaviors of AI into different states. For example, enemy can have different states like idle chase, attack, et cetera. Each state will be a different class that will run on our state machine where using state machine for managing states. We could also done this by using enum states, Just like how we managed the states of the players attack, right? But the problem with using enum states is that it doesn't scale well when we have lots of states. If you're planning to build a complex I, then the code will become a mess. If you use the Enum approach, using a state machine is much more scalable and it can handle more complex cases. We're going to go with that before we start the implementation. First, let me explain to you the architecture of state machine and how it'll work. Each state will be a separate class like this. Here I'm showing the Chase state for example. Each state will have three functions, enter, execute, and exit. As the name suggests, the enter function will be called when we enter the state, and the exit function will be called when we exit the state. Then we also have the execute function. The execute function will be called every single frame while the state is active. Okay, If you take the example of the chase state, we can do things like play an audio from the enter function to let the player know that he has been spotted. Then from the exit function, we can play an audio to indicate that the enemy lost the player. And from the execute function we'll have the right logic for chasing the player most of the times the main logic of the state will be in the execute function. Now we should have a basic idea of what we're going to build. Let's go ahead and start the implementation. First, I'll create the enemy controller script for controlling the enemy under the scripts folder. I'll create a new folder enemy. In here I'll create a new C sharp script called Enemy Controller. All right, this script will be responsible for controlling the enemy. Similar to how the player controller controls the player. But the main difference is unlike the player controller, the enemy controller will not use the player's input to control the enemy. Instead, it'll use the state machine to run different states of the enemy based on what's happening in the game. All right, we need to go ahead and build our state machine that the enemy controller can use. Let me go back to Unity. Under the assets, I'll create a new folder called Util here, I'll create another folder called state machine. The reason why I'm putting this in a folder called utual is because state machine is something that we can reuse in multiple games. Usually I'll just build one state machine and reuse that in all my games. I'd like to consider this as library that I can re use in multiple games. And that is the reason why I'm putting it in ut that I can easily move it into different products. Okay, here I'm going to create two new scripts. The first one will be called State machine and the second one will be called State. All right, so let me go ahead and open these two in which the studio first let's look at our state machine script. State machine is going to be a plain class, we don't have to inherit from the mono behavior. All right, the owner of the state machine will create the instance of it directly. This won't be attached to any, kay, object. I also make the state machine class a generic class by adding this over here. The reason for this is because the state machine can be used for different purposes, not just for handling the states of the enemy, for example. It can also be used to handle a NPC in, again, it can even be used to handle states of UI. If you have watched my RPD series on Youtube, then you'll know how useful state machines are for handling things like UI states. The point is, since this can be used for handling multiple things in, again, we want to make this a generic class. Every time I create an instance of this class, we'll also specify the owner of this class. This over here will be the owner of the state machine. For example, when we create an instance of the state machine, let's say we want the state machine to handle the enemy states. Then we can just define it as a state machine of any controller. Okay? If you want to use it for something else like handling the states of NPC, then you can go ahead and make it a state machine of NPC controller. So that is the reason why we are using generic here and making the state machine a generic class. We have already used generic classes in this course, but this is the first time that we are defining a generic class, okay? For example, when we create a list like this, this is actually a generic class. Here, we can create lists of different types, right? This can be a list of indure, list of string, Yeah, these are generic classes. We have been using them, but this is the first time that we are creating it. All right, so this will be our state machine class. Next, let's go to the state class. The state class is actually going to be a mono behavior because we want to attach it to a game object. Then state class is also going to be a general class because we should be able to specify the owner of a state class. All right, This is going to be the base class and all the states in our gains are going to inherit from the state class, okay? Inside the state class. First we'll define the enter function. So let me just create a public function called the enter function is going to take the owner of the state, so let me create parameter for the owner. This function is not going to have any depition because this is a base class. When we inherit the state class from our states like Idle and Chase, then we can overwrite these functions and the implementation of those functions will be written in those subclasses, okay? Since we want to be able to override this function from the subclasses, we have to make it a virtual function. Let me add a virtual keyword at the start. Okay? So this will be the enter function. It'll be called whenever we enter the state. Next, let me go ahead and create the execute function. All right, so this will be the function that executes the logic of the state, and this will be called every frame while a state is active. Okay, finally, let me just copy this and create the exit function. All right, for the exit and execute functions, we don't want to take the O as the parameter because we can just cache it when we get it from the enter function. All right, these are the functions that we need in the state class. Now back in a state machine, I'll create a property, the current state of the state machine. So let me just create a public property of type state and I'll call this current state. Okay, I'm just making the setter private so that we won't be able to change the value of this property outside this class. All right, next, since the state machine is a plan C sharp class, we'll be creating an instance of it using a constructor. It won't have start wake functions like the monobehavior class, right? So let's define a constructor over here. The constructor will take the owner of the state machine as a parameter. All right, we can just cast the owner to a private variable since we'll need to use it from other functions. All right. Next I'll create a function for changing the state. So let me call this change state. And this function will take a state as a parameter. All right, and when this function is called, we have to switch to the new state that's passed to this function right from here. First I'll exit the current state by calling current state it function. All right, here I'll just add an unconditional operator just because when we call the chain state for the first time, the current state will be null and order to throw an exception in that case, okay? So after exciting the current state, I'll change the current state to the new state that's passed, and then I'll go ahead and enter the new state. Okay? And when we enter a state, we also have to pass the owner. So let me go ahead and pass that out. Right? This function will change the current state for us. Next, I'll create a function called this function will execute the current state for us. From here I'll just call current state execute. Okay? Yeah, these are all the functions that we need in our state machine. So now we can go ahead and add different states and try testing them. All right, so back in Unity, let me go to the scripts folder, and inside the enemy I'll create two new scripts, Idle state and Chase state. Okay, so these two are going to be the states of the enemy. And we have to make it inherit the state class. Instead of inheriting from mono behavior, we'll inherit from state. And this is a state of the enemy, right? So I'll pass the enemy controller as the owner. Okay, from the state we have to override the enter, execute and exit functions. And we have to write the behavior for what should happen in each case. First, let me override the enter function for this type override and space. You can see all the functions that we can overwrite from here. If I set up the function, you can see that it automatically creates the code for us. Okay? So this function should have the behavior that should happen when we enter the idle state. The actual implementation of the state's behavior will be done in the next video. For now, I'll just write p dot lock statements and make sure that our state machine is working properly. Here I'll just lock something like entered idle state. Okay, So next let me go ahead and overwrite the execute function. I'll just type over write. And if I hit space, we can see the execute function and then pressing Enter will automatically create the function for us. All right, from here I'll just print executing idle state. All right, and finally I'll go ahead and now write the exit function. From here, I'll just print exiting idle state, okay? So let's also do the same thing from the Chase state. First we have to make it inherit the state class, all right? Then we have to define the enter execute an exit functions, I'll just copy it from the idle state. And here instead of printing idle I'll print chase. Okay, so we have to find the two states of our enemy. Now from the enemy control script, we have to create a state machine first and then set the state as idle state and then run the state machine, okay. First let me create a property for the state machine. All right, so this will be a state machine of enemy controller. I'll make it a property with the private stor. All right, then from the start function I'll go ahead and initialize the state machine. Okay, so we have to initialize it using the constructor. While calling the constructor, we also have to pass the owner. The owner will be this class itself. We can just pass this keyboard for the owner. Okay, So this will create an instance of state machine and store it in our state machine property. Next we have to set the starting state of the state machine. I'll call state machine chain state. For the state, we have to pass the reference of the idle state. Since all these are going to be attached to the same game object, we can go ahead and use get component to get the reference of the idle state class. All right, soon we'll be optimizing this by caching all the states so that we don't have to call get component each time. All right, so we have to set the starting state to idle. Next from the update function we have to call state machine execute to run the state machine every single frame. All right, let's go ahead and test this. First we have to attach all of these scripts to our enemy game object. First, let me attach the enemy controller and then I'll attach the idol and J states. All right, so now if you're on the game, you can see that in the console first it printed entering idle state and then it just keeps printing executing idle state, right? That's because we set the starting state as idle state. First, enter the idle state and it'll keep executing this function. Executing idle state. All right, our state machine is working fine. Next, let's also try switching from the idle state to the chase state. For that, what all Dos in the execute function of the idle state? I'll check if the player pressed a button. If the button is pressed, then I'll switch to the chase state, okay? I'm doing this just for testing in the actual idle state behavior, the switch to the chase state will only happen when we see the player, right? But right now, since we don't have all those behaviors implemented, I'll just check for test input. And then switch to the chase state. Okay? I'll check if the key is pressed. All right, D for test. If that is pressed, then we can go ahead and change the state to state. To change the state first, we have to get reference to the state machine of the enemy controller. We have the enemy controller in the function cache it into a private variable. I just call it enemy. I'll cache it from the function. Okay, so now we can call enemy state machine chain state to chain state. We can get a reference to the chain state by calling enemy dot component chase state. Okay? This will work, but it's not the optimal way to do it because calling the get component every time like this is a bad thing for the performance. We have to cash this somewhere and use that for that. What I'll do is in the enemy controller, I'll cash all the states of the enemy first, create num called enemy states. All right, so right now we only have idol and chase states. We have to catch the reference of the idol and chase state. To do that, I'm going to use a dictionary. If you have not used dictionary before, it's somewhat similar to a list, but the main differences for the indexes are always an integer value that starts from zero, right? But in the case of dictionary, we can have any type of index, like string or even an enum. Okay, In the case of dictionary, the indexes are actually called a key. For our dictionary, the key is going to be the enemy states enum, the value is going to be a state class, right? So let me just call the subject state dict for short. And then from the start function, first we have to create an instance of this dictionary. All right? And then we have to cash all our states into the dictionary. Okay, first let me cash the idle state. The key of the dictionary is going to be enemy states. Idle enum, we can get the value of the dictionary, which is the reference of the state class by calling the get component function and getting the idle state. Okay, So next we also have to do the same for the J state. So let me go ahead and do that. All right, all states are cash now. Now instead of calling get competent every time we can get the value from the dictionary Here I'll pass of enemy stated. Okay. Now we can also use it from all the other places instead of calling it competent from here we don't have access to the state dictionary. What I'll do is instead of making it public, I'll just keep things encapsulated by creating another function called chain state. Okay, This function will take the enum of the state. All right, from here we can just call state machine chains. State. And for the state we can pass state dictionary of the enum. Okay, This way we don't have to expose a dictionary. I think having a public function like this is much better than exposing our dictionary. All right, now from here we can simply call enemy chains. State for the state, we can pass enemy state chase. All right, so the code is really short now and it looks much cleaner. That's right. So now when you run the game and press the key, we should actually switch to the chase state. Okay, so let's go ahead and test that. All right, so right now we are executing the ideal state. But if I press the key, okay, I have to be focused before pressing the key. All right, now when I press the key, you can see that we exited from the ideal state and we entered the state and started executing the chase state. All right, this is how the flow of the state machine will work. The enemy controller will always run one of the enemy states based on what's happening in the game. All right, obviously we don't want to just print these messages, instead we want to implement the actual behavior, right? We'll start doing that in the next video. Yeah, I'll stop the video here and I'll see you in the next video. 16. Chasing the Player: In the previous video, we implemented the state machine and we created two states for testing it. But right now, the functionality of these two states are not implemented. We'll be doing that in this video. The functionality that we want to implement is when the enemy spots the player, he should go to the chase state and start chasing the player. All right, first we have to implement the functionality for detecting the player. For detecting the player, what I'll do is I'll create a spear trigger on the enemy. Whenever the player enters that spear trigger, we'll start tracking him. If the player is also in the field of view of the enemy, then that means the enemy can see the player and we can make the enemy start chasing the player. Okay. First under the enemy, I'll add a new empty game object called Vision Sensor. Okay? So this will be the sphere trigger for detecting the player in here. I'll just click on Add Component and add a Sphere Glider. All right, right now it's really small. We want the few range of the enemy to be much bigger. I'll just increase the radius to something like six. You can increase it further if you want your enemy to have a longer vision range. Okay, next we also have to set the trigger to true to make a trigger. We'll also create a new layer for the vision sensor. Let me go ahead and add a new layer. I'll call this one Vision Sensor. And then back in the game object, I'll change its layer to Vision sensor. All right, next, we only want the vision sensor to detect the collision with the player. It's not detect collisions with any other objects. Right, to go the project settings and under physics, let's find the layer collision metrics. We only want the vision sensor to collide with the player. Let me remove everything else. All right, now we have our vision sensor. Next, when the player enters the vision sensor, we have to start tracking him. Right? I'll create a script for doing that inside scripts in the enemy folder. I go ahead and create a new script called vision sensor. Okay, whenever the player enters the vision sensor trigger, the on trigger enter function will be invoked, right? So let's go ahead and define that function. From this function. We have to start tracking the player track in the enemy controller. I'll create a list of Me Fighter called Targets in range. Okay, why am I making this a meal fighter instead of the player controller? The reason is because in the future you might also have other allies of the player that the enemy might want to attack. Saving the targets as a meal fighter is better than saving it as a player controller. Okay, I also have a list here in case there are multiple allies and the player that the enemy wants to track. All right, let me also initialize this list from here so that we don't get any error when we use it. All right, now from the trigger Er function first we have to get the Mele fighter component of the collider. So I'll just say other get component and I'll get the mele fighter component. All right, let me just throw this innovariable called fighter. If fighter is nautical, no that means the collider that entered the trigger has a mile fighter component. In that case, we can go ahead and add that to this list in the enemy controller. Okay, first let me grab reference to the enemy controller. So I'll make it a stilizield variable over here. All right, now we can go ahead and add the fighter that entered the trigger to the targets and range list. Okay, this will start tracking the player when he enters the targets in range list. By the way, it will not track the enemy even though the enemy has the Mele fighter script. Because the vision trigger will only collide with objects in the player layer. All right, next, when the target moves out of the vision trigger, we have to stop tracking him. For that, we can use the on trigger exit function. This will be worked whenever a collider exits the trigger. From here we have to stop tracking the target. So we can go ahead and call the remote function on the targets in range list. Okay, Now we are keeping track of the targets that are in the enemy's vision range. But the thing is the enemy should only be able to see the target if the target is also in his field of view. Okay, so what we can do is from the idle state we can loop through all the targets in the targets and range list and check if any one of the targets are in the field of view of the enemy, okay? And if they are in the field of view, then we can set them as the target that the enemy must chase. Okay, so let's go ahead and do that on the idle state. So first of all I'll just remove all the deeper clock statements. We don't need them anymore, we just wrote that for testing the state. Okay, now from here I'll use it for each loop I loop through all the targets in the targets and range list of the enemy, okay? And then we have to check if any of these targets are in the enemy's field of view. Right, in the enemy controller. Let me go ahead and define a property for the field of. I'll create a float able called it's a shorter field of few, let me make it a property. And I'll send its value to 180 by default. Okay. I'll also make it a sized field so that we can edit it from the inspector. All right, now from here we can check if the target is in the enemy's field of view. Do that first, I'll find the vector from the enemy's position to the target's position. All right, and then we can find the angle between that vector and the enemy's forward vector to check if the target is in the enemy's field of view. Okay, so first let me find a vector from the enemy position to the target position. So we can do that by subtracting the position of the enemy from the position of the target. Okay, let me just store this innovatible called vector to target. Okay? And then we can find the angle between the enemies forward vector and the vector to target. Let me show this inevitable called angle then. If the angle is less than O equal to enemy's field of divided by two, then that means the target is in the enemy's field of view. Okay, By the way, the reason why I'm dividing the field of view by two is because the angle can be in the left or right direction. Right. The target can be at 60 degrees to the left or 60 or 70 degrees to the right. In both these cases, he is in the field of view of the enemy. All right, if the target is in the enemy's field of view, then we can make the enemy start chasing the target. Right? First for I'll do is in the enemy controller, I'll define another property called target. All right, this is the target that we want to chase From here I'll sit the target to the target that is in the enemy's field. If you, then we can go to the chase state and start chasing the target. To chase the target, we can switch to the chase state, called enemy chain state, and I'll pass the chase state. All right, and finally, let's break out of the loop so that we won't try to do this for the rest of the targets in this list. Okay, so let's score it and try testing this. We have to attach the vision sensor script. Let me go ahead and do that. And here we also have to assign the enemy reference. Let's try testing this now Let me just bring the player down so that it's not in the field of view. By default picking us control shift to place the players feet exactly on the ground. And let's try testing it now. All right, let me just turn on Gizmos and set up the enemy from the inspector so that we can see the vision trigger. All right, now when we enter the vision trigger, so you can see that the enemy is able to detect and he switched to the chase state. All right, so a code for decking the player is working. And next let's also try entering the vision trigger from an angle that is outside the enemy's field of view. Okay, so in this case you can see that the enemy is not able to detect us. But as soon as we enter the enemy's field of view, the enemy will detect us. And let's switch to the chase state. All right, next, when the enemy detects the player and goes to the chase state, we have to make the enemy chase the player, right for moving enemies or any other AI characters. We can use Amish and Unity. It's navigation system works by defining a mesh like this. All right, so this blue color is the Amish and that's the area in which the AI characters can walk. We'll be using this for moving our enemy. First, we have to take a Nash for this level. In our level we have two things, a plane and a cube, right? These are the ugly environment objects that we have. What I'll do is I'll put these two in another object called environment. All right, let me make the cube and play a child of its environment. If you have a lot more game objects, then you have to put all those in a parent object like this. Then you have to mark the environment object as navigation static. All right. I also want to change all the children. So let me just press Yes. The reason why we're doing this is because when they are baking abmish, only the objects that are marked as navigation static will be considered. Okay, so let's try baking an Amish first the window and open the navigation window. All right? I'll just tock it over here. Then under the Bake tab, we can just go ahead and click on Bake with the default settings. All right, you can see this blue mesh our scene, so these are the areas on which our air characters can walk over. Here you can see that we don't have the blue mesh in the place where the cube was placed. That is because the player won't be able to walk in that area. Okay, another thing that you have noticed that whenever you change the static game objects in your scene, you'll have to bake the Nash again. Okay? So just keep that in mind. So now we have Amish en, we can walk on next to make the enemy move. We also have to add a Nabmish agent component to our enemy. So let's go ahead and do that. I'll add the naming component and let's just leave all the settings at its default value. Now from our chase state, we can make the enemy move towards his target by using the Amish. All right, so first we have to get the reference of the Amish. Let's do that from the enemy controller so that we don't try to get the reference multiple times. If you do it from the enter function of the chase state then the issues we'll be calling the chase state multiple times. And every time we call it we'll be grabbing reference to put all those things in the enemy controller. All right, from here let me catch a reference to the names agent from the start function. Okay, by the way, to be able to use the Nama agent class, we have to import the humanity engine namespace. All right, I'll just name this Nab Agent shot. Okay, and let me also make the property so that we can access it outside this class. All right, let me catch a reference to it from the start function. Okay, and now back to the chase state function. Let me get rid of all the deputed dot log statements. And then to be able to use snapmsh agent, first we had to cast the reference to the enemy controller. So let me go ahead and do that. Okay, I'll cast the owner from the enter function. Then from the execute function, we can use the amash agent of the enemy to make the enemy his target. Right? So we'll make the Nabs agent motor position. We can use the set destination function and set a destination for the Nabs agent. All right, so in this case the destination will be the position of the target, right? I'll pass the position of the target as the parameter. And this should make the enemy chase the player and go to the chase state. Okay, let's go to it and try testing this. All right, so if I enter the vision trigger, the enemy is not chasing the character. There's some issue that we have. That's because we have apply rote motion turned on in the animator of the enemy. We can just turn it off for now and we can turn it on when we are performing some action that has rote motion. Okay, now the enemy should be able to chase the player when we enter the vision range. Yeah, you can see that the enemy is chasing the player. But there are two problems. The enemy is not playing any animations while moving. And the enemy is stopping on top of the player, right? That looks really weird. We want the enemy to stop at a distance from which he can perform attacks, okay? So make the enemy stop at a distance. We can use the stopping distance property of the Napa agent. We can also set it from the code. Setting it from code will be better because depending upon the states we might want to use different stopping distance. From here we can go ahead and set the stopping distance of the naps agent for the state I want the enemy to stop at, around 3 meters in the player. Okay. And I'll just make it a las field variable so that we can control it from the inspector. Let me just call it something like distance to stand. And I'll make it three by default. And I'll set that variable here, Okay. Now if we test the game, the enemy should stop at 3 meters and he should not move to the players position. All right, so you can see that is working, okay. So the next thing to fix is we want the enemy to play the running animation while he's chasing the player. We can easily do that by setting the move amount parameter of the enemy's animator, right? First we need a reference to the animator components. Reference to it from the enemy controller. Okay, let me create public property here and then I'll go ahead and catch it from the start function. All right, so now we can set the amount of the enemies animater based on the speed of the Nab agent. Okay, So down here I'll call enemy animator set float function to set the amount parameter. And the value of this parameter should be set based on the speed in which the apperent is moving. Right in the abating class, we have a property called speed, but this is actually the maximum speed in which the navchine can move. It's not the speed at which the Nabachgent is moving right now. To get the current speed of the navaent, we have to use the velocity property. Since velocity is actually a vector, we have to get its magnitude, okay? This will give us a speed in which the navigant is moving. The value of the move amount should be 0-1 If you look at the animator, let's open the Locomotion blend tree. You can see the value of the move amount should be 0-1 All right, we have to map the speed of the Napa agent 0-1 by normalizing it. We can easily do that by dividing the current speed of the Napa agent by the maximum speed in which it can go. Okay, let me divide this value by the maximum speed of the Na agent. Okay, so now our enemy should also play the animation while moving Tscl, Unity and Test. All right, so yeah, I can see that the enemy is playing animation while moving. All right on E. Last thing I'd like to fix is right now when the enemy turns, you can see that he's turning really slowly. Even though he's playing the running animation, I want to increase the speed at which the enemy turns so that it looks more realistic. We can do that by changing the angular speed property of the lab agent. So let's increase it to a high value like 720. Now the enemy should turn really fast, okay? So I can see that the enemy is turning really fast. All right, now our chase functionality is looking fine. I'll start the video here and in the next video we'll start implementing the rest of the states. So watching and I'll see you in the next video. 17. Combat Movement: Hey phone. In the previous video we made the enemy detect the player and chase her when she's in the field of view of the enemy. In this video, we're going to start the implementation of combat movement. Let me explain what I mean by that. We're going to implement a combat system similar to the one that you see in games like Assassin Street and Batman. In the system, the enemy won't keep attacking the player all the time. Instead they'll stand at the distance from the player and circle around her like this. And we'll only attack the player one at a time. Okay, so if you played games like Assassin Crito Patman, you should be familiar with this combat system. In our implementation, once the enemies chase the player and disclose to her, they should either stay idle in a guarded position or circle around the player. Only one of the enemies should actually attack the player at a time. All right, in this video we'll start implementing the part where the enemy stands and circle around the player. What I'll do is I'll create a state called combat movement. In this state, the enemy can do three things. The enemy can stand close to the player while playing a combat idle animation. Or the enemy can circle around the player, okay? Finally, if the enemy is not close to the player, then the enemy will chase the player, okay? So the state will be called combat movement and it'll handle all the movement of the enemy once a player or any other target is detected by the enemy. Okay, so just remember in the state, the enemy can either stand in a alerted position or circle around the player or chase the player. Okay, so let's go ahead and start the implementation of this. First, let's go ahead and change the implementation of Chase state. Now Chase won't be a separate state. Instead we'll have a combat moment state that will handle Chase, combat idol and circling the player. By the way, if you want, you can keep them as separate states. But the reason why I'm combining them into a single state is because these states have a lot in common. All these three states handle the movement of the enemy after the player is detected, tried. It makes sense to combine them into a single state. We have to create a state called combat movement. What we can do is we can actually rename the Chase state to combat movement state. Instead of creating a new one. As well as right lick and select. Rename, Rename this to Combat movement state. Okay, and by the way, in the enemy controller, I'll also rename the name of the Enum so that it doesn't cause any confusion in the future. Okay, so in a combat moment state, we have to handle combat, idle chase and circling the player. Right in here I'll use Aum to differentiate between those three states. So let me create num called AI combat states. And this can be idle chase or circling. Okay, by the way, note that the idol that we have out here is different from our idle state. This idol is a combat idol in which the enemy has spotted the player and is aware of the position of the player right in this idle state. We'll be playing a different animation. And we'll have to do things like make the enemy face the player and the player, okay. So these two states are not the same. All right, so we have three enum states here. Now from the execute function, we should really keep setting the destination of the nav agent to the player's position if are in the chase state right here. What we can do is we can write if conditions to check in which state we are. Okay. By the way, before that we actually have to create a beatable of state. Let me read it over here. Okay? And now from the excrete function, we can check in which state we are. So first I'll check for idle, and then I'll check for chase. And finally I'll check for circling. Okay, and we surely set the destination of the dam agent to the player's position. If we are in the chase state. Let me cut this and pace it over here. By the way setting, the more amount should be done from all the states. I'll put it outside. If conditions only, then we'll get a smooth transition to running and idle. I'll put this outside all the conditions, okay? Next, if you are in the idle state or circling state, if the player runs out of the attacking range, then we have to go back to the chase state and start chasing the player again. Right? Regardless of what state we are in, we have to always go to the chase state if the player goes far away from the enemy. Right from here we can check if the distance between the player and the enemy is greater than a certain threshold, okay? So I'll use the vector three distance function. And I'll check for the distance between the position of the player and the enemy. So we can get the player from enemy target. Okay? And we also have to pass the position of the enemy. So this will check for the distance between the players and the enemy's position. And if that is greater than the distance at which the enemy is supposed to stand, then we have to go back to the chase state, right when we are checking this distance. I'll also add one to the distance to stand. The reason is because if the enemy goes to the chase state, while the player makes small ppens, that will look pretty unrealistic. For example, if the player is in the range of the enemy, and then if the player moves by a small amount, like 0.2 meters, In that case the enemy should not go to the chase state and move 0.2 meters, right? That will look, we, we need a threshold above which the enemy should start chasing. We can actually turn this into a variable in case we want to change it from the inspector. I'll just call this a just distance threshold. Let me set it to one by default, okay? And if this condition is true, then we have to go to the chase state, right? For that, I'll create a new function over here called start chase from here, state to chase, okay? In the future, we'll also have to do other things from this function. That's the reason why I'm making this a separate function instead of writing it directly over here. So let me call this function from here. Now, if the distance between the enemy and the player is greater than a certain threshold, then we'll go to the chase state. And chase the player, okay? Next. While we are in the chase state, if the distance becomes less than equal to the distance to stand, then you have to go to the combat idle state. What I'll do is every time we are in the chase state, I check if the distance to the player is distance to stand. So let me just copy this condition. Okay? And in this case we should check if the distance is less than or equal to the distance is stand by the way to the distance to stand value. I'll also add a small float value, like points three. The reason for this is because distance to stand is actually the stopping distance of the nav agent, right? The navient will stop at the distance to stand distance. But when we calculate distance like this, there is a chance that it can be a little above than the distance that was calculated by the nav agent. Just to be safe, we can add a small value so that this condition will be true before the nav agent stops, okay? So if this is true, we have to go to the idle state, okay? So from here I'll call a function called start idle. And then I'll just return because we don't want to set the destination of the navigant again. Okay, So let's go ahead and create the start idle function. All right, from the Unction. First of the state to combat stated. Then while we are in the combat idle state, we have to play a different idle animation. Where the character has his guard up right. In the combat idle state, the character does know that he is in combat. We do need a different animation for that. We can simply use our normal idle animation. So let me go to Miximo and find an animation for combat idol. All right, so this is the animation that I want to use. You can find it if you search for Swat idol. Okay, I have already downloaded this animation, so let me go ahead and import this into Unity. So this will be under combat. All right, so we have to rig this animation. First, let me change the animation type to human Eid and I'll tell a copy from definition. And the will be Erica Archer, Avada. Okay, now we should be able to preview the animation on the player. All right, this is the title animation that you want to use while we are in combat. You want this animation to loop, right? I'll turn on loop time and loop pose. Then I'll also change all the based upon to original. I'll check back into pose for all the root transforms because we have a loop match for all of it. Okay, so let me go ahead and hit Apply. Now we can add this animation into our animator controller. Let me take the animator here, I'll rack and drop the idle state. Let me just call this combat idle shot. We have to make a transition from locomotion to combat idle. We also have to do the reverse. Let me make one back to the locomotion. Okay, so we switch to the combat title animation. Then we set a parameter from the code here. I'll create a Bolling parameter. I'll just name this something called combat mode. And if that is true, then we have to go to the combat title state. Okay, and by the way, we have to make sure to turn off has exit time because when the combat mode is true, we don't want to wait for the locomotion to complete. We want to switch to the combat title immediately. Okay, next let me set off the transition back to the locomotion. And here also I'll turn off the Has exit time. And in this case the condition will be combat mode equal to fats. Right? When combat mode is false, we have to go back to the locomotion. Okay, so we have set up the combat idle animation, but we need to make a small improvement to this. Just adding the animation like this will have a problem. But I'll show you the problem first and then we'll do the improvement. All right, back in our code when we start the idle state, we also have to set combat mode to true. From here I'll get the enemy's animator and I'll use the set bull function and set the combat mode parameter to true. By the way, we also have to set this to faults when we start chasing because we don't want the player to be in the combat idle animation while chasing, right? Okay, so this is all we got to do. Let's code Unity and try testing this. All right, so it works, but there was a small problem. The problem is while stopping to the combat idol animation, the enemy character is sliding for a small period of time, right? So let me show it to you again. Okay, so you can see the enemy character was sliding for a small period of time. This was the problem that I was talking about. The problem is the transition from the locomotion to combat idle state doesn't look good, right? We could fix this by making an improvement here. What I'll do is I'll just delete this. Instead, I'll duplicate the locomotion and I'll rename it to combat title. Okay, so this is actually a blunt try, right? Our locomotion was bluntry. But here what we want to do is we want to replace the first animation with our combat idle animation. Okay? So yeah, we have to actually dragon drop the clip in case of bluntries. Okay, So this is pretty similar to our locomotion plenary. The only difference is the first animation is the combat idol animation and not our normal idle animation. Okay, so this will help us to make the transition between the locomotion and combat idol animation smoother. All right, from here we can go ahead and make the same transitions that we made before. The condition will be combat mode equal to true, and we have to turn off the exit time. Then I'll also make a transition back to the locomotion, and this time the condition will be combat mode equal to false. Here also we have to turn off the exit time. Okay, so now the transition between the locomotion and combat title will be a lot smoother. The enemy character should no longer slide. Let's go ahead and test that. Okay, so this is better, but there is actually a little bit of sliding in between few frames. We could fix that by moving the code for setting the move amount into the update function of the enemy controller. This shoes only have it over here. It won't be executed during the frame in which the return is called. Okay, so we could move it into the update function of the enemy controller so that it will always be called. Here we can access directly, You don't have to call enemy dot. Okay, so let's try testing this now. All right, now the transition to the combat idol looks much better. Okay, so now we have implemented combat idol and the chase state in the combat movement state itself. Next we have to implement the circling state. I'll be doing that in the next video. I think we have covered enough for a single video. Thanks for watching and I'll see you in the next one. 18. Combat Movement || - Circling around the Player: In the previous video, we started the implementation of the combat Mopen state. In this video we'll continue our work on that and we'll make the enemy circle around the player randomly when he's in the combat Mopen state. All right, let's start the implementation of that. In the previous video we did define the circling state, but while we are in the circling state, we are not doing anything right now. Okay, the way that we won't implement this is the enemy should randomly circle around the player while we are in the combat movement state, right? So implement that. What I'll do is while we are in the idle state, I'll set a timer, and once that timer becomes zero, I'll switch to the circling state. Okay, so that's how we're going to implement this. First, let me create a float variable for the timer, all right? We consider it to zero by default. Then when we start the idle state, we consider the timer to some value like three or 4 seconds. If you want to make it more interesting, we can even set it as a random value between a range. That is what I'm going to do over here. I'll create a new serialized field patable of type two. I'll call this for an idle time range. Okay, let me just give it a default value. I'll just set it to 2.5 By default, the idle time should be a random value, 2-5 from here. To set the value of the timer, I'll call the random dot range function. For the main value, I'll pass idle time range x, and for max value, I'll pass idle time range y. Our rights and all the value of the timer will be a random value between these two ranges. Next, we have to decrease the value of the timer from the execute function. From here I'll check if the timer is greater than zero. If that's the case, I'll go ahead and determine the value of the timer by time delta time, Since the execute function is called once every frame. What we're doing here is reducing the value of them by the time that is past every frame, okay? So this is just a simple way of creating timers ingenuity. Once we set a value for the timer from here, it'll keep decreasing until it becomes zero, okay? Now, from the ideal state, if the timer's value becomes less than or equal to zero, that means the time that we set for the ideal state is over now. And now we can go to the circling state, okay? So from here to make the circling state even more random, what I'll do is once the time of the ideal state is complete, I'll go to the circling state 50 percentage of the time, and in the other 50 percentage of the time, I stay in the ideal state itself. Okay. When we are here, there is a 50 percentage of chance. We'll go to the circling state or the ideal state. To achieve that, what I'll do is I'll use the random range function to generate an integer value 0-1 Okay? So the value returned by this function will either be zero or one. It will not return decimal values 0-1 It'll either return zero or one. Okay? That is because we are passing integer values as the parameter. If you were passing float values, then this function would return decimal values between the ranges. But in our case, since we're going for 50, 50 chance, we just want to generate a value that is either zero or one. Okay, and here you might be confused by why I am passing two over here, even though I want an integer value 0-1 The reason for that is because in the integer version of the random range function, the max value that we pass is exclusive. Okay? So here you can see that the min value is inclusive and the max value is exclusive. Okay, But in case of the float version of the rando dot r function, both the min and max values are inclusive. All right, that's weird thing about the rando dot range function, so you have to be careful while using it. In our case, we're using the integer version and we want an integer value 0-1 Since you're looking for 50% of chance, we can just check if the value returned by this is zero. Since this function either turn zero or one, this means this condition will be executed. 50 percentage of time, right? 50 percentage of the time. We'll stay in the idle state itself. Let me call the start idle function again. Then in the other 50 percentage of the time, we have to go to the circling state and start circling around the player, right? To start the circling state, I'll call start circling function, but we haven't created that yet. Let's go ahead and create that. Okay, so from this function, first I'll set the state to AI combat state start circling. And then the circling should be done for a certain period of time, so we can use our timer for that, just like we used in the idle state. Okay, so here I'll define another variable for the circling time range. Okay, let me define a vector two and I'll call this circling time range. The value of this will be, let's say 3.5 or maybe 3.6 just to make it a little higher. Obviously you can change these values from the inspector and use the value that you like. Okay, now from the start cycling function, we can generate a value between our circling time range. So let me just copy this function. I'll change it from idle time range to circling time range. Okay, so next we have to determine the direction in which we'll be circling. The enemy can either circle towards the left or right. Okay, so what we can do is 50% at the time, we can make the enemy circle to the right and the other 50 we can make him circle towards left. Okay, so here again I'll use a random range function. I'll be using the integer version of this function, and I'll generate an integer value 0-1 If this is equal to zero, then we can circle towards left, and otherwise we can circle towards right. Okay, what I'll do is I'll create an integer variable here. I'll call this circling direction. Let me set it to one by the forward, for the left direction. I'll set the value to positive one. And I'll set the value to negative one for the right direction, okay? 50% of the times the value of the circling direction to one and the other 50 begins to minus one, Okay? So let me show the value returned by this conditional operator in the circling direction variable. All right, circling direction will also be random. Next we need to find the animation to play while we're circling. We can't just use the normal locking animation, that won't look good. Let's go ahead and find a good animation for that from Ximo. This is the animation that I want to use. You can go to Miximo and search for Sword. You'll find this animation. We need this animation in both direction, left and right. This one is left, but we also want the one in the right direction. Okay, this one is right. So go ahead and download these two animations. I have already done that. Now let's go ahead and import those two animations into Unity. So let me just drag and drop it in here. Okay, these are the animations. So we have to go ahead and make it humanoid. All right, and now we should be able to preview the animation on our player. So this is how the animation will look like. Okay, while you're here, let's turn on loop time and loopholes because we want this animation to loop. For this animation, it's really important that we change the root transform rotation to original. Because for this animation, the character is not moving in the direction in which she's facing right. Instead she's moving towards the side of the direction in which she's facing. It's really important to make the original. For most of our animations, we used original as based upon. Tried, but in case you script this part, it might be okay for other animations, but it can cause issues with this animation. Okay, I'll also change the transform position, exit riginal. I'll check back into post for rotation and position y because they are having a loop match. Okay, so let me go ahead and hit Apply and they also have to do the same for the other animation. So first I'll check loop time and loopholes. I'll make the based upon original and then I'll check back into post for the rotation and position y. Okay, so now let's go ahead and add these animations to our animator. What I'll do is, since we have two animations that should be played based on the direction in which we are going, I'll put these two animations in aplentry. From here I'll create a new plentary. I'll call this one circling. Okay? In this splintere we'll have two motions. The parameter that we're going to use for this splintere is going to be a circling direction. Okay? In the parameters, I'll add a new integer variable called circling direction, and that is the one you want to use over here. Okay, So I guess we have to make the parameter a float only then it'll be shown in the parameter drop down of the blend tree. So let me just let this and add a float parameter called circling direction. Now it should be shown in the drop down, okay? Even though we're using a float parameter here, the value that we will be setting to it will be an integer, right? That won't be a problem. Okay, Next, the threshold of the circling direction should be negative one and positive one. We don't want to use the automated threshold checkbox. If you turn it off, we'll be able to enter the threshold nally threshold will be negative 1.1 when the value of the circling direction is negative one. I want to play the right animation. We can't copy the X file, We have to copy the clip while we're using Glentary. Let me go ahead and do that. When it's negative one, we'll play animation. When it's positive one, we'll play left animation. Okay, now we can try playing the animation. Negative one, the character should walk towards his right. When it's a positive one, the character should walk towards his left. Okay, that is working. Next, circling, we have a transition from the combat idle state to the circling state in the animator, right? I'll create a bulling parameter for that called circling. And then make a transition from combat idle to circling while the circling parameter is true. Okay, so here in the condition we can check if the circling rapid is true and we have to turn off the has exit time because we don't want to wait for the combat title to complete. Okay, next we have to make a transition back from circling. I'll create a transition back to the combat title. This will happen when the circling becomes false. Okay, So this is how our animator will be set up. Now from our code, we just have to set these parameters. All right, from the start cycling function. First I'll set the circling parameter. So let me call the set bold function of the animator and set the value of circling to, okay? And then we also have to set the circling direction. Since the circling direction is a float parameter, we have to call the set float function. We can set the cling to the circling direction that we found over here. Okay, By the way, when we start the idol or the chase state, we have to make sure to set the circling parameter back to falls. So let's go ahead and do that. Okay, so it falls when we start the chase or idle state when we start circling is setting the primer and we are playing the correct animations. So now the only thing that's left to do is actually to move the enemy character around the player in a circle. Okay, so we have to do that from the execute function. If the state is circling, right, to rotate the enemy around the player, we can use the rotate around function of the transform. In this function, first we have to pass the position around which we should rotate. We should rotate around the player, right? Let me pass the position of the player as the first parameter. Okay, if we can get that from the target property of the enemy. All right, as the second parameter, we have to pass the axis of rotation. The axis will be the y axis. We can just pass vector three up. Then we have to pass the angle by which we should rotate every frame. Okay? We can consider this as the speed in which the enemy should circle. We can just create a variable for that. I'll just call that circling speed and also it to 20 by fold, okay? Now from here we can pass the circling speed as a third parameter, but we also have to multiply it with a circling direction, right? Only then we'll circle in different directions based on the value of this variable, okay? Finally, we also have to multiply this time delta m to make it frame right independent, okay? So this will rotate the enemy around the player. Finally, once the time that we set for the circling state is over, we have to go back to the idle state. Right from here I'll check if the timer is less than O equal to zero. If that's the case, I'll go ahead and call the idle function to start the idle state. I'll also return from this function because we don't want to execute this line, okay? So this is all we have to do to make our enemy rotate around the player to score Unity and try testing this, okay? So the enemy should circle around the player after staying in the idle state for some time. All right? So you can see that the enemy started circling around the player. And he goes back to the idle state again. Again, he starts circling, okay, yeah, that is working fine. The enemy will stay in the combat idle state and then circle around the player at random times. Now we can try adding another enemy to the scene and see how that looks. Okay, let me just move it a bit towards the left and now we can see how it looks. Okay. Yeah, you can see both of them are circling and by the way, you can see that when they collide, they'll automatically move out of the way since they have a Nab meshed agent on them, but it's not perfect. You could see that they were stuck for a few seconds before getting out of the way. Yeah, it's not perfect, but we'll improve that in the future. For now, I think this looks okay. Both our enemies are circling around us, similar to how they do in the combat systems of games like Assassin Street. All right, so I'll stop the video here. Thanks a lot for watching and I'll see you in the next video. 19. Improving Circling: In the previous video, we made the enemy circle around the player like this. But our implementation has few issues. Right now we'll be fixing those issues and improving our implementation in this video. First, let me explain the issues to you. The first issue that we have is the enemies will try to walk through obstacles like this. Okay? They won't be able to pass through the obstacle because they have character controller, but still they'll keep trying to walk through the obstacle. The reason for this is because we're using the transform rotate around function for moving the enemy in a circle. Right? All this function will do is try to move the enemy in a circle. It won't care if there are any obstacles in the way. Okay, that is an issue that we need to fix. This issue will also happen when there's another enemy in the path of a circling enemy. All right, in that case, since both enemy have Nabs agents, they'll try to push each other while an enemy is being pushed. It'll play weird jittery animations like this. Okay, We need to fix these two problems in the implementation of circling. The problem with our current implementation is that we're using transform to trade round function to move the enemy in a circle. And this function won't care about the obstacles of other enemies in our way. Instead of this, we can use the move function of the Namgent. Yeah, here you can see the Nabhan has a function called move. If we use this function for moving the enemy in a circle, then it don't try to move into obstacles because Nabhan will be aware of that, right? The bosh will move if the position to which we are trying to move is inside the Nash, okay? We can use the move function of the nav agent to fix this issue, but when we use this function, we don't have an easy way to rotate around the player like this. We'll have to write this logic on our own. All right? We'll have to find a vector that we can pass to the move function so that the nav agent will move in a circle. Okay, let's write the code for finding the vector that will make our enemy move in a circle. For achieving this, we can use the same logic that we used for rotating our camera around the player in our third person set up. Okay, what we can do is first we can find a vector between the player's position and the enemy's position. And then we can rotate that vector by multiplying it with a coternion. Okay, so first we need to find the vector from the player's position to the enemy's position. Okay, so let me call this something like vector to target. And since you want the vector from the player's position to the enemy's position, we have to subtract the player's position from the enemy's position. Okay, so let me go ahead and do that. All right, so the player will be in the target of the enemy. So let's get its position. And this will give us the vector from the player's position to the enemy's position. Okay, now we can rotate this vector by multiplying it with the quaternion. Let me create a conin by using the Ton oiler function. We want to rotate this vector in the y axis, right? In the y parameter of this function, we can pass the angle by which you want to rotate. The angle will be circling speed into circling direction into time delta. Okay, let me copy that and base it over here. All right, and we can multiply this anion with our vector to target. This will rotate this vector by this angle. Okay? So let me show this in another variable called rotated position. All right, so now we have the position to which our enemy should move. But we can't pass this position directly to the move function because the move function accepts the offset. Okay? You can see here it accepts the offset which is the vector from the enemy's current position to the rotated position, okay? We can easily get that by subtracting the vector target from the rotated position. All right, this will make the enemy move in a circle by using the Nab agent. All right, let me get rid of the transformed rotator around function. We don't need that anymore. By the way, you might be wondering why I'm using the move function here. Instead of using the set destination function of the nave agent right here. We could also use the set destination function and set the position directly instead of finding the offset and all that. But the problem with using the set destination function is that it won't move the nerve agent if our new position is very close to our current position, okay? And in our case, the two positions will be very close because we are multiplying it by time, Ta, time, every frame, belly move the character a little bit, Okay, The destination won't work in that case. By the way, we could also try to find the destination when we start circling and find a position on the circle to which the enemy should move. In that case, we don't have to use time Ta time because it's only done once, not every frame. But the problem with that approach is the navigant will just move the enemy in a straight path. Kate won't take a circular path. That's the reason why we are using the move function instead of that destination. All right, this will move the enemy in a circle. Next, While moving the enemy, we also want the enemy to face towards the player at all times. Right? That was already handled by the transformed or rotate around function that we used earlier. But now since we're using the move function, we'll have to handle that manually. But it's pretty easy to achieve. We just have to make sure that the enemy is rotated in the opposite direction of the rotated position vector. Okay, I'll set the enemy rotation to the negative of our rotated position vector. So let me just use the conk rotation function to convert the rotated position vector into a con. In here we have to pass the negative of the rotated position. All right, This is all you have to do to move the enemy in a circle by using the nave agent. But if it test the game right now, you'll see that the enemy is still playing the strafing animation when he's next to an obstacle. The reason for that is because we are always playing the circling animation when we are in the circling state. That's right. Instead of doing this, we should only play the circling animation if the enemy is actually moving. Okay, if the enemy is not moving because of some obstacle, in that case, we should not play the circling animation. So we have to make sure that the enemy is only playing the circling animation when he's moving. Okay, to achieve that, what we can do is we can play the circling animation based on the velocity of the enemy. If the enemy did not move in the current frame, the velocity will be zero. When it's zero, we don't have to play the circling animation, but if the enemy actually moved in the current frame, the velocity will be a value greater than zero. And in that case we can play the circling animation. Okay, we can play the circling animation based on the velocity of the enemy, just like we did for walking animation. So here we're playing the walking animation based on the move amount parameter which we set as the velocity of the nav agent. Right? We can do something similar for the circling animation, but one main difference is that the circling animation should only be played when the enemy is moving to the side, right. We should not play the circling animation when we are moving forward. For playing the circling animation, we should consider the part of the velocity to the left or right side of the enemy. We should not consider the forward component of the velocity, right, even here we're using the entire velocity for controlling the work animation, right? But this is not really the right way of doing it because for the work animation, we should really consider the forward component of the velocity. The reason why we had that jittering animation while an agent was being pushed is because we are considering the entire velocity, not just the forward component of the velocity, okay? This solution is not enough. Instead Tiara, Tu is split the velocity into its forward and sideward component. And then use the forward component for the walking animation and the sideward component for the strafing or circular animation. We can call it whatever we want. Okay, we'll be using a little bit of math to achieve this. First, let me explain to you how we are going to implement this. Let's say this is our enemy and he's facing in this direction. This is forward vector. Let's say this is the velocity in which he's moving. Okay, now we have to split this velocity into its forward and sideward component. So that we can use the forward component for playing the walking animation, and the sideward component for playing the strafing animation. Okay, we can split the velocity vector into its forward and sideward component by using trigonometry. If we say the angle between the forward vector and the velocity vector is theta, then velocity multiplied by cos theta will give us the horizontal component of the velocity vector. The horizontal component is the component in the forward direction. The vertical component will be velocity multiplied by sine theta. Okay? The vertical component is the sideward component. In this case, if a velocity vector is V, then the forward component of the velocity will be cos theta. The sideward component of the velocity will be B sine theta. Okay, this is how we're going to find the forward and sideward component. All right, go ahead and start implementing this. First we need to get the velocity of the enemy. We can get it from navigation do velocity. But it won't work for the circling animations. Because for circling we're using navigation do move function, right? When we're moving the navigation like this, the velocity component will be empty. This will only have a value when we're moving the naviation agent by using the set destination function. Okay? So we can't get the velocity like this. So we'll have to calculate the velocity mannerly. What is velocity? Velocity is displacement by time, right? The velocity in this current frame will be the displacement of the enemy in this current frame divided by the time taken for the current frame, okay? Velocity will be by dt, dx is the change in displacement and it is the delta time. Find the displacement of the enemy in the current frame. If that's what I'll do is I'll store the previous position of the enemy at the end of the frame. Okay, here let me create a vector three for saving the previous position of the enemy. And then at the end of the update function, I'll go ahead and save the position in the previous position. Okay, so now we have the previous position and we can find the displacement by subtracting the previous position from the current position. Okay? So let me show this in available, called delta position. Now we can find the velocity by dividing delta position by delta time. Okay? So this is the velocity of the enemy in the current frame. Okay, Next we have to split the velocity into their forward and sideward component. Right? We know that the forward component of the velocity will be V costa. That's actually an easier way of finding the value of V costa. We don't have to take the angle and find the case and all that. Instead we can do it by taking the dot product between the velocity and the forward vector of the my. Okay, So the value of this will be equal to costa. And if you don't know why it is, let me explain. The doc product between two vectors a and B will be a, B, cosceta, right? If we take the dot product between the velocity and the forward vector, we will get cos theta. But since we know that the forward vector is a normalized vector, meaning its length will be one, right? Since we know it's length will be one, we can replace by one and we'll get cost. Okay? The dot product of velocity and the forward vector will give us V Costa, let me show this invariable, I'll just call this forward speed, and then we can set the move amount past the value of forward speed divided by the max speed of the navigant. Okay, now for the walking animation, we will only consider the forward component of the velocity. Now if an enemy gets pushed toward the site, he won't play the forward walking animation. Okay. By the way, to reduce the jitter that we get while playing the animation, we can also pass a damping value while we set the parameter here. I can pass a dam time. As a third parameter, I just pass something like 0.2 When we pass the dam time, we also have to pass the data time to let me go ahead and pass that. All right, so this will set the move amount more smoothly. Next we need to find the sight word component of the velocity for playing the strafing animations. Sideward component will be sine theta. To calculate that, we can just find the angle between the forward vector and the velocity and then take sine theta of the anger. Okay, we have to find the angle between the forward vector and the velocity. For that I'll use vector three. Sine angle function will give us the sine angle. Which means the value returned by this can be positive or negative. We want that because based on the value of this, we should determine whether we should go to the left or to the right. Okay, So I'll use the signed angle function and I'll find the angle between the forward vector and the velocity vector. Okay, When using the signed angle function, we also have to pass the axis around which we should take the angle. That should be by axis. Let me pass vector three up over here. Okay, let me stow this innovable called angle. Now I can find the sine of the angle. I'll use math of sine function. And for the angle I'll pass the angle per. But one thing you have to notice is that the sine function takes the angle in radians, not in degrees. Okay, here the sine angle will return the angle in degrees, which is what we're used to. But for the sine function, we'll have to pass the angle in radians. We can easily convert the angle from degrees to radiance by multiplying it with math, degree to radian to, for short. Okay? This will give us the value of sine theta. And we know that the site word component will be velocity multiplied by sine theta. But in this case, I don't want to multiply it with the velocity, because Cinta will give us the value between -1.1 right in the animator. That is what we want. The circling direction is a value between -1.1 We can simply go ahead and use this value. We don't have to multiply it with the velocity. Let me just throw this innovaable called strafe speed. Then we can set it into an animator parameter. I'll use animator set float function. The parameter that we used for controlling strafing was called circling direction. I'll just change it to speed because that name makes more sense. In this case, let me just pass the value that we calculated for the straight speed, then I'll also pass a dam time. All right, so this will make sure to smoothly set the straight speed. By the way, let me change this from more amount to forward speed. We'll change the name of the parameter in the animator. Also, I just think that forward speed makes more sense than mount, since we are only considering the forward component of the velocity. Now we have to go to the animator and make sure that we'll play the strafing animation based on the value of the straight speed. Okay, previously we were playing the safing animation based on two parameters. A boling parameter called circling and another flow parameter called circling direction. Now instead of that, the safing animation should be played entirely based on the safe speed parameter. All right, to make things simpler, what I'll do is I'll create a new blendree with all the animations. It'll contain idle, walking, running animations, and also the left and right strafe animations. Okay, so for that we'll need a two dimensional blende. Let's go ahead and create that. I'll go ahead and add a new state from Blendtre. I'll just call this combat movement. All right, this blinry should play different animations based on two parameters, forward speed and stave speed. Okay, So we'll have to make this a two dimensional blendry instead of a one dimensional blendry. If you click on this, we can change the blend type. I'll change it to D freeform directional. Now this will ask us to specify two parameters. First of all, let me just rename the move amount parameter to forward speed because we changed it from the code. Then let me also create another parameter called straight speed. Okay, let me just put it right below the forward speed. Our two rebrand, Trey will work based on the value of forward speed and straight speed. Here the first parameter will be forward speed. And we can change the second one to stave speed. Okay, now we can add different motion fields here. The first one will be the combat idle animation. That should be played when everything is zero, right? Let me just drag the clip into the first field. This will be played when both forward speed and straight speed is zero. All right, next I need to find the walk and run animations. They are in the locomotion folder, let me just drag and rub them. Walk will be our second animation. Walk will be played when the forward speed is 0.2 or more. Right, actually let me switch the position of forward and stray speed because it feels weird to have the forward speed in the x axis. I want the straight speed in the x axis and forward speed in the y. So I'll just change the x to straight speed and y to forward speed. Okay, here the value of x will be zero. And the value of y should be 0.2 because that's the threshold for playing the walking animation, right? If you remember, that's how we implemented the locomotion planter. Okay, so next let's add the running animation. All right, so in case of running, the straight speed will still be zero and the forward speed will be one. Next, let me add two more fields for strafing left and strafing right animations. Okay, let me go ahead and attach the strafing animations to those field. First I'll attach the strafing left animation and then I'll attach the strafing right animation. Okay, for both strafing animations forward speed will be zero. Then for the strafing left animation, the straight speed will be minus one. For the strafing right animation, the strap speed will be one. Okay? This is how our blend tree will be created. Let me show you how it works by playing the blend tree. Okay, When both these variables are zero, we are playing the idle animation. But if I mow it in the forward direction, you can see that the player starts walking. All right, and then if we move towards the left, she'll play the strafing left animation. And if we move it towards the right, she'll play the right animation. Okay, by the way, if we have values in both the straight speed and the forward speed, then it'll play a blend of the strife and the walk animation. But they don't look really good. We're not going to use them anyway. In our case the player will either be strafing or walking forward. The case where we might get a mixed value is when a character is pushed by another character. In that case, the character might go in a diagonal direction. It might play a blend. But in most normal cases, we'll either play the strafing animation, the walking animation, or the running animation. Okay, using a blend tree like this is much easier than creating two dibles and transitioning to the circling blind tree. Now we don't need these two plant trees anymore. We've combined everything to combat movement, right? We have to make transitions to and from the combat movement tree. Should go to the combat movement when combat mode is true. All right. Should go back to the locomotion when the combat mode is false. Okay, This is what we have to do. And by the way, we can go ahead and delete the circling and circling direction parameters because they're not used anymore. And we can also remove the lines for setting the circling and circling direction parameters. Okay, let me go ahead and remove all those. All right, finally one thing we have to do is that since we renamed our parameter from mount to forward speed, we should also make sure to change that in the player script here, there are two places where we're setting the mount parameter. Since we changed its name to forward speed, we'll also have to change it from here. Okay, let me just copy this and place it over here also. All right, so this is all you got to do. So let's go ahead and test the game. Now when an enemy is being pushed to the side, he's playing the strafing animation like before. The enemy is not playing the forward walking animation while being pushed to the side. We don't have those weird structures of animations before. By the way, pushing the enemy like this is not a desired behavior. We'll improve this in the future and make the enemy stop circling instead of pushing other enemies to the side. But when we have lots of enemies in the scene, there will be little pushes here and there. It will be good to play the correct animation based on the direction in which the enemy is being pushed to, instead of always playing the forward working animation. All right, next let me test how the enemies circle around static obstacles. Let me go and stand near this cube and the enemy should circle around it. Here you can see a beard issue. You can see that the enemy is not circling past this line. What's happening is when the enemy passes that line, the pash agent is pulling the enemy back towards it. Okay, Now the reason for this is because the destination of our nappih agent is still set to the position of our player. When we try to move our nap agent while the destination is set, then the naps agent will try to make sure that it's in a position where it can view the target. Okay, This issue is cost because the destination of the enemy, staph agent is still set to the players position while we are circling. You're setting it from chase, but it will remain the same while we are in the circling state, right? We have to reset the destination when we start the circling state. To do that from the start circling state, we can call enemy navigant reset path. So this will reset the destination of the enemy. So this should solve issue. So let's go to DM, tritting this, okay? Now you can see that the player is able to circle past that point. And we don't have the startling issue that the Nab Mach was causing earlier. All right, now the player is circling fine. When he reaches the obstircle, he'll just move back so that he can complete the circling. Okay, by the way, before testing this, I increase the circling time so that I can show you the issue easy, just in case if you're wondering why the enemy is circling nonstop. That's the reason I just increased for testing it. Yeah, we have improved circling of enemies. In this video, we have fixed some edge cases that we had in circling. I'll drop the video here. Thanks for watching and I'll see you in the next video. 20. Attacking the Player One by One: In this video will make the enemy attack the player right. Now the enemy will chase the player and circle around him. Next we have to make the enemy attack the player. In three flow combat systems, all the enemies should not attack the player at the same time, right? If they all attack at the same time, then the player won't be able to fight multiple enemies. Instead of that, the enemy should only attack the player one at a time, okay? So while implementing attacks, we can't just start attacking from the combat movement state. If we do that, then we won't be able to make sure that only one enemy is attacking at a time, right? Instead what we'll do is we'll create a script called Enemy Manager to manage all the enemies that are in the player's range. Then we'll pick one of the enemies and make him attack the player. All right, let's go ahead and implement this inside scripts inside the enemy folder. I'll create a new script called Enemy Manager. The script will be responsible for managing all the enemies that are in the players range here. First created list of enemy control and I'll call this Enemies in range. Okay. Then we need to create functions to add and remove enemies from this list. First mated public function called add enemy in range. This function will take the enemy that we should add. Okay, from the function. I'll go ahead and add the enemy to the enemy syn range list. All right, just to make sure that we don't add an enemy twice, I'll make sure that the enemy range list doesn't already contain the enemy that we're trying to add. Okay? So contains function to check that we are only added if the list doesn't already contain the enemy that we're trying to add. Okay, so next, a great function for removing an enemy from the enemies in range list. And from the function we can just go ahead and remove the enemy from the list. All right, so next we have to call the add enemy range function when the player is in the enemy's range. And we have to remove the enemy when the player goes out of the enemy's range. Okay, so we can do that from the mission sensor script. So this is a script from which we are detecting the player right from here. When we detect the player, we can also add the enemy to the enemy in range list. So let me just add a brace over here. I add another line for adding the enemy to the enemy in range list. But we don't have a reference to the enemy manager yet, right? If you want to, can create a sateliz field variable to get a reference to the enemy manager class. But since enemy is a manager that will only be created once in the scene, there's actually a better way of getting the reference to the enemy manager. We can use the singleton design pattern for this. For that, all you have to do is create a public static instance of the enemy manager and then use that instance to access it. Okay, I'll create a public static instance. I'll call this for short. Let me make it a property with a private stor so that we won't be able to set its value from outside this class. Then we can initialize it from the awake function. Okay, from the wake I'll sit. The value of I to this, this war will give us the reference of the class we are in. Okay. Creating a static reference like this will only work if this class will only be created once in a scene. All right, so keep in mind that you can't use this technique for other classes like enemy controller, for which we need to create multiple instances. All right, now since we have a static reference, we can go ahead and use that from our vision and script. From here we can just type enemy manager to get the instance of the enemy manager. Now we can go ahead and call the ad enemy in range function and add this enemy to the enemies in range list. Okay, Next, we should also remove the enemy from the enemy in range list when the player goes out of the enemy's range. All right, let me just add braces here and I add another line for removing the enemy from the enemies in range list. Okay, I'll call Remove Enemy in range function and pass the enemy. That's all I have to do for tracking the enemies in range. For testing this, we can make this enemies in range list public so that we can see its values from the inspector. We can change it back to private once with the testing. Okay, so let's test and see if it's working. So let me go to Unity. First we have to attach the enemy manager script to a game object. Here, I'll just create a new game object called Enemy Manager. All right, let me just reset its position to zero. And I'll go ahead and add the enemy manager script. Okay, now when you run the game by default, there shouldn't be any enemies in the enemies in range list. But if we go close to an enemy, you can see that they are added to the enemies in range list, right? Then if I run far away from those enemies, they'll be removed from the enemies in range list. All right, so that's working. Let me just change it back to rip it since we should not be able to addit this from outside the enemy manager class. All right, now we are tracking the enemies that are in the range of the player. Next, we should set up one of the tracked enemy and make him attack the player. All right, in our combat system, we want the enemy to attack the player one by one. After each attack, I want to wait for a few seconds before performing the other attack. This will give time for the player to fight back and it'll make sure not to overwhelm the player with attacks. Okay, so we need to wait for a few seconds between attacks to implement this, what I'll do is I'll create a variable called not attacking timer. All right. This timer will be updated when none of the enemies are attacking the player. Once this timer reaches a threaten threshold, we can select an enemy and make him attack the player. Okay? Once the attack is over, we'll update the timer again. Once it reaches the threshold, we'll select another enemy and make him attack the player. That's how we're going to implement. This will be done from the update function. Let me go ahead and overwrite the update function. And from here we should update the not attacking timer if none of the enemies are attacking. Right, So how can check if none of the enemies are attacking the player? For that, we can use the any function and check if any of the enemies are attacking the player. And then we can just negate it to check if none of the enemies are attacking the player. Okay, let me go ahead and use the NE function on the enemy's range list. To use the NE function, we have to import the link namespace. All right, in this function we have to check any of the enemy in the enemy's and range list is currently attacking the player, right? To check if the enemy is attacking, we can just check if they are in the attack state. Okay, we haven't implemented the attack state yet. We only have the idle and combatant state right now. Let's also go ahead and create the attack state in the scripts folder. I'll go ahead and create the attack state. And by the way, to keep the states organized, we can create folder called states inside the enemy folder. We can put all our states in the Okay, now let me open up the attack state script. All right, so this is going to be a state of enemy controller, so we'll be doing the implementation of the attack state later. For now, we just need class to check if the enemy is currently attacking. Okay, in the enemy controller, we also have to add the state to our state dictionary. So first let me add it to the enemy states enum, all right, And then we also have to add it to the state dictionary. So let me go ahead and do that now from the enemy manager script, we can check if any of the enemies in the attack state. By the way, right now we don't have any function for checking the current state. So we can get the current state from state machine, current state. But this is actually the state class, right? We can't really compare it with the enemy states. Um, okay, that won't work. To make the simple or we can do in the enemy controller, we can create a public function called is in state, okay? So this will take a state for checking if the current state of the state machine is equal to, equal to the state that is passed into this function. So we can turn the Enum into a state class by passing it into our state dictionary. All right, so in this way we can check if the current state is equal to the anim state that was passed, and we can just return the value of this, okay? By the way, this function should return a buying because it's checking whether or not we are in the state, okay? If we are in the state that was passed the function, then this function will return true, and otherwise it will return false, okay? So now from here we can go ahead and use the S in state function and we can check if the enemy is in the attack state, okay? So this will not true if any of the enemies are in the attack state, okay? But what we want to check is if none of the enemies are in the attack state, that is when we should update the timer, right? So we can just negate this, and this will be equvalent of checking if none of the enemies are in the attack state. Okay, so let me put this in condition, and if none of the enemies are in the attack state, we should go ahead and update the attacking timer. Okay, so just go ahead and determine the not attacking timer by time delta time, the photoing this. Let me also check if the not attacking timer is greater than zero because I don't want to reduce the value of this timer past zero. Okay, if none of the enemies are in the attack state, we'll update the attacking timer. If the attacking timer reaches zero or a negative value, then it means it's time for us to select an enemy and attack the player. Okay, so we should attack the player from here. For that first we have to select an enemy from the enemy's range for attacking the player. Okay, So let's go ahead and create a function for that. I'll create a function that returns an enemy. And I'll call this function, select enemy for attack. Okay? And from this function we can just choose an enemy from the enemy's range list. If you want, you can just choose a random enemy from this list. But make things more interesting, what I'll do is I'll choose the enemy that was in the combat movement state for the largest amount of time. Okay, if an enemy has been waiting in the combat movement for a long time, then we'll give priority to that enemy performing the attack, okay, to people. To do this first we have to keep track of how long all the enemies have been staying in the combat movement state. Okay, for this what I'll do is I'll create a new variable in the enemy controller here. Let me just create a float variable. I'll just call this compact movement timer. I'll actually make it a property and let me set its default value to zero. Okay, And now when we enter the combat movement state, we can set the combat movement time to zero, okay? And then from the execute function of the combat womment state, we can increment the combat woman. So let me go ahead and do that. Okay, and finally, when we exit the state, we can go ahead and send it back to zero. All right, now we are keeping track of the time for which the enemy is staying in the combat movement state. We can go ahead and use that here and find out the enemy that has been waiting in the combat moment state for the longest. Okay, for this what I'll do is first I'll sort the enemies in range list based on the value of the combat movement timer. To sort a list, we can use the auto by function. In this case, we want to sort it in the descending order, right? The enemy with the highest combat movement time should be the one that we select. Okay, I'll go ahead and use the order by descending function. And we have to order this based on the value of the combat movement timer. Okay, let me pass that. After sorting the list, we can just return the first element from it. Okay, so let me just go ahead and return this. This will give us the enemy with the highest value in the combat movement time available. Which means it will give us the enemy that has been waiting for the longest amount of time in the combatant state. All right, by the way, one thing I want to mention is that this is not the most efficient way of getting the enemy with the highest compat popen timer in terms of performance. Okay, simply writing a for loop and using a variable to keep track of the maximum compat popen timer would be more efficient. But I'm just going to use this because this only requires a single line. It doesn't make a big difference unless you have lots of enemies in your game. Okay, so if you're like making a game with thousands of zombies in it, then you probably don't want to sort the enemy's list. Instead, you should use a single far loop and find the enemy with the largest combat moment timer. Okay, so just keep that in mind. Don't use this approach if you're planning to have thousands of enemies in your slee. All right, so let's go ahead and call this function from here. And I'll show the returned enemy inavailable called attacking enemy. Okay. Then we have to make this enemy attack the player right? For that we can this change the state of the enemy to attack state. Okay. And finally, we should set the not attacking time available to some threshold so that we won't attack the player again immediately. Okay, So we can just set it to two or 3 seconds to make it seem natural, we can actually use a random value, Okay? A random value 1-3 will work fine. By the way, let's just make this utilized field variable so that we can wreak it from the instructor without changing the code. Here, I'll go ahead and create a vector two variable called time range between attacks. Okay, let me get a default value of 1.4 All right, now we can go ahead and use that in the random range function. All right, now we're picking an enemy and changing state to attack for attacking the player. But right now we haven't implemented the attack state, We need to implement that next. But right now we have another here, it says that we already have another definition for the attack state. That's because in our male fighter script we have enum called attack state. What we can do is we can rename this to Attack States instead of attack state. So I'll just use control R R. And I'll rename this to Attack States. Okay, But that did not rename any of the instances, because these instances are still referring to the attack state class that you created over here. What we can do is we can change everything. I'll use control and search for attack state, okay? And then we can replace all the instances of attack state by attack states. Okay? So we can go ahead and click on the replace button that will replace all the occurrences. But one thing to note is that it will also change the attack states that we have over here. Here, we only need one is all right, now all the others should be fixed, okay? So now we can start doing the implementation of our attack state class from here. First we'll go ahead and override the enter function. And from the enter function at cashptance to the enemy controller, just like we do from all the other states. All right, next, the first thing that the enemy has to do from the attack state is to get close to the target so that he can perform the attack, okay? While the enemy is in the combat movement state, he'll be standing at three meter distance from the player, right? But to perform an attack, the enemy needs to come closer to the player. What we can do is we can change the stopping distance to something smaller, like 1 meter from the attack state. Let's go ahead and do that from the Enter function. I go ahead and change the stopping distance of the bash agent, and we can create a stylized field variable for that so that it can be changed from the inspector. Okay, I'll just call this one attacks and I'll set its value to one by deferred. All right, now let's set it as the stopping distance. After changing the stopping distance, we can keep setting the destination of the naps agent from the execute function to make the enemy move closer to the player. Let me go ahead and write the execute function. From here I'll go ahead and set the destination of the Naps agent to the position of the player. We can get the player's position from the target property of the enemy. All right, I forgot to call the set destination function. Let me go ahead and do that. This will make the enemy move closer to the player for performing the attack. So next, once enemy is in the attack distance, we can go ahead and perform the attack, right? We can go ahead and calculate the distance between the player and the enemy by using the vector three distance function. Just like it did from the combat mint state. So let me just copy this if condition and paste it here in the attack state. In this case, we should check if the distance between the enemy and the player is less than or equal to the attack distance, okay? They're just adding a small value over here in case if the distance computed by the Napa agent is a little bit higher, okay? If the enemy reached the attacking range, then we should go ahead and perform the attack. For that, we can go ahead and create a function. I'll create Tine, because we want to wait until the attack is over. Let me just call this attack. Okay. While the enemy is performing the attack, the machine should no longer move closer to the player. This line should not be executed while the attack is being performed. Prevent this. What we can do is we can create a Bollin variable called is attacking. Okay, at the start of the courting attacking to true. At the end al falls at the start of the execute function. If it attacking is true, then we'll just return and we won't execute any of the code below. Okay, This will make sure that the enemy won't keep chasing the player while they're attacking Next. From here, we should actually make the enemy perform the attack, right, since we made our code modular. And since the code for performing the attack is in the merely fighter script, which is common for both player and the enemy, we can go ahead and reuse this code for the enemy also. Okay, so to perform the attack, all you have to do is call the tried to attack function. Right now we're already calling it for making player perform the attack. But we can do the same for the enemy also. Okay, from the attack state first we need a reference to the male fighter. We can actually go ahead and cache reference from the enemy controller, just like we do for the nav agent animator and all that. Let me just duplicate this line and create a property for the male fighter component. I'll just call this fighter for short. And then I'll go ahead and catch it from the start function. Okay, now from the attack state, we can access the mere fighter component of the enemy. From here, we can call the trite to attack function to make the enemy perform the attack. Okay, This will make the enemy perform the attack. We should make the code wait until the enemy completes performing the attack. Right after that, we should set the attacking defaults. How can we know when the attack may be complete? If you look at the attack cotine in the male fighter, you can see that once the attack is complete, set the attack state back to idle. Okay, we can check the value of the attack state to wait until the attack is complete. But the at tax state right now is a private variable. We can go ahead and make it a public property with a private stor that it won't be able to change its value, we'll be able to get its value. Okay? And by the way, since it's a standard to make the first letter of property upper case, I'll just make the upper case over here. All right, now from here for wait until the attack is over, we can just say turn new wait until we can keep waiting until the value of the attack state is idle. Okay, so let me get the attack state from enemy to fighter. And we can wait until its value becomes equal to idle. All right, this will make it wait until the attack is complete next. Since we have turned off the root motion of the enemy, by default, we have to make sure that it's turned on while we perform the attack. Okay? Because we can have attacks that has root motions in it. For example, we can have an attack where the character jumps and performs a swing. In such cases, we want to use the root motion of the animation while the attack is being performed. We have to enable the root motion. We can go ahead and do that. From here, I'll set the apply root motion property of the animator to true before we start the attack. Once the attack is over, I'll send it back to false. All right, this is all we have to do to perform the attack. Now we can go ahead and call the attack routine if the enemy is in the attack range. Let me go ahead and call it from here. All right, this is all we have to do from the attack state. Now we can go to Unity and attach the attack state to our enemies. By the way, it's time that we make our enemy a prefab so that we don't have to make changes to all the instances of the enemy in the game folder, I'll create a new folder called prefabs, and we'll go ahead and turn our enemy into a prefab. Okay, so let me just lead the other one and make the duplicate of the enemy again. So now both the enemies are a prefab. All right? The good thing about making them a prefab is that when we want to make a change to it, we can go inside the prefab by pressing this button and make the change from here. In this case, you want to add the attack state, we can add it from here inside the prefab. Now if you go back, it should be added to both the instances of the enemy. All right, so it's really important to create a prefab before you create multiple instances of game chicks. Next, we also have to set up things like attacks and the sword of the enemy, right? For the enemy, I'll just give two attacks. The first one will be, the second one will be horizontal, just like our player by the way, you can go ahead and find different attack animations for the enemy. But since this is just tutorial, I'm just going to use the same attacks for player and the enemy. Okay, next we have to create the sword for the enemy. This model already comes with the sword. If I collapse of the thing, we have a game object called Sword over here. But that's not actually, for some reason, the naming of these game objects are wrong. This is actually the swarm object. Okay. But this is actually a skinned mesh renderer, Which is a mesh that we use for body parts of the character. So I don't want to use the sword, instead I'll just use a model with a normal mesh. So let me just disable this for the enemy. I'll just use the same sword that we used for the player. Okay, let me find the player sword. We can actually go ahead and click on it from here. Okay, by the way, you can go ahead and find the separate sword for the enemy. But I don't want to spend time on things like that because this is just editorial. So let me just turn the sword into a prefab, and I'm going to use the same one for the enemy. So let me go inside the enemy prefab. Let me find the right hand of the enemy. Okay, I'll just keep expanding until I find the right hand. Here it is. Let me go ahead and attach a sword into the enemy's right hand. All right, it is positioned correctly. One important thing that we have to do is we have to change the layer from player hit box to enemy hit box because this is a hip box of the enemy. Right? Next we also have to assign the sword into the Mealy fighter script of the enemy. So let me go ahead and do that. All right, so now we have to set up the Mealy fighter of the enemy so that you can perform attacks. By the way, if you have attacks like punches or kicks, then you also have to set up spear colliders on the hands and feet of the enemy. Just like we did for the player right here, The player has spear gliders on all the hands and feet. But I'm just going to script that step for the enemy because the enemy has Swat attacks. Okay, so that's all we have to do. So let's try testing this. Okay, looks like we have an error, so let me see what's happening. It's in the enemy manager script that's happening because there are no elements in the enemies in range list. To prove that error, what we can do is if enemies range count is equal to zero, then we can just return. And we don't have to execute the code for selecting the enemy to attack. Okay, While we're here, let's also make sure that the enemies in range list is initialized by default, okay? If it's not initialized, then we'll get a null reference exception and we try to use it. So now we can try testing this again. Okay, so now we have a missing component exception. It's telling us that there is no sphere Glider attached to the left hand object. We haven't attached spear colliders to the enemy because the enemy doesn't have attacks like punches or kicks, but we still have this exception. Let's go to the line that is causing the error, okay? It's the disabled hit boxes function here by just disabling everything, even if that collider doesn't exist. From here begins to a simpler check to prevent that from happening, I'll check the left hand collider is nautical only then I'll execute this line. Okay? So I can do that for all the gliders, even for the Swat glider. Okay, so let me also do it for the other gliders. Okay, so I've added to check for all the gliders and now we shouldn't get that error. So let me go ahead and test the game again. And this time we don't have an errors, so let me go near the enemy. Okay, it looks like we have another reference exception. Let's see what that is. It looks like we are trying to perform an attack even before we set a target for the enemy. Okay, we can debug this issue by adding a break point and attaching this to humanity. When you do that, the program will stop executing at this line. From here, we can check what's causing the error. In the debug mode, we can how our any variable and we'll be able to see the value of that variable. Okay, if you look at the target of the enemy, you can see that it's null. That means we are going to the attack state even before setting the target. All right, fix this issue. What we can do is we can just set a small value for the not attacking timer by default. Right now, since it'll be zero, we'll start choosing an enemy for attack as soon as the player enters the enemy range. Okay, so we don't want that by default, we can set this to a small value, like 2 seconds. All right, now let's try testing this. Okay, so now that error is gone, and you can see that the enemy moved close to the player and attacked him. Okay, the code for making the enemy attack is working fine. But right now, the enemy keeps attacking the player again and again. Right? Instead of this, we want the enemy to move back after attacking, and we should give a chance for the other enemies to attack. Okay, same enemy should not keep attacking the player. Instead, all the enemies in range should attack him one by one. We'll be implementing that in the next video. I'll hop the video here. I think we have covered in for a single video. I'll thank watching and I'll see you in the next on. 21. Retreating after Attack: Here in this video, we'll make the enemy retreat after performing the attack that it will give a chance for other enemies to come and attack the player. In the previous video, we implemented the attacks, but right now the enemy keeps attacking the player. And the other enemies just keep circling without getting a chance for the attack. Let's make our enemy retreat. After performing the attack first, we need to find a walking back animation for making the enemy retreat. This is the animation that I'm going to use. You can just search for back backward, walk sword and you'll find this animation. All right, I've already downloaded this. Let me go ahead and import it to Unity. So my animations folder, I'll the backward walk animation in here. Okay, so how to read this. So let me make it humanoid copies from oval Erica Archer. Okay, now I should be able to preview the animation. All right, I want the salmation loop. I'll turn on loop time and loopholes. I'll make the based upon original for all the three root transforms. Since the root transform rotation and position y is a loop match. I'll go and check bake into force with them. Yeah, this is how the animation looks like. Now we can go ahead and add it to our animator. We could add this to our combat movement plan tree itself. That way we don't have to set any parameters, we just have to move our player back. When we do that, the forward speed will be negative. We can set up this plant tree in such a way that when the forward speed is negative, we'll play the backward walk animation. Okay, so I select the blunt tree and I'll add a new motion field. Should perform the backward walk animation when the x is zero and when y is a negative value, right? The y here is the forward speed. In case you don't remember if the forward speed is a negative value, then we can play the backward walk animation. So let me go ahead and drag this clip in here. Let's try playing this now. If I move the forward speed to -0.2 then you can see that the character is working backwards. All right, so that is working fine. Next we need to write the code for making the enemy retreat. What I'll do is I'll create a new state for this inside enemy, inside the state's folder. I'll go ahead and create a new fee shops script. I'll call this retreat after attack state. Okay, and let me open it up in visual studio. I'll get rid of the default code. This class will be a state of the enemy. I'll make it inherit state of enemy control. Okay, next I'll override the function of the state from the function. I'll just catch a reference to the enemy so that we can use it throughout the class. Okay, so next, still go ahead and override the execute function. The actual logic of retreating will be implemented in this function. From here, we just have to move the enemy back, right? How can we get the backward direction? Our forward direction is the direction towards the player. We just have to take the negative of that, and that'll give us the backward direction. Okay, first I'll find a direction towards the player, So we can get that by subtracting the enemy's position from the player's position. The player is inside enemy target. To get the player's position like this, I'll subtract the enemy's position from it. Okay, this will give us a vector towards the player. Let me just throw this in Avatablerv target. This is the forward direction. We can just negate it to get the backward direction, and we can move the enemy in the backward direction. To move the enemy, I'm going to use the navigant move function, because this will make sure that we won't move the enemy through an obstacle. Okay, in here we have to pass the offset by which we want to move. So we can get that by taking the negative of the vector to target and multiplying this with the speed. Okay, The speed, I'll just create a srilized field variable over here. Let me just call this backward walk speed. I'll just add it to something like 1.5 Pretty fault in here. We can multiply the direction with the speed. We also have to multiply it with time, tela time. All right? And by the way over here, we only want the direction of the spector, right? So we have to normalize this next. While the enemy is walking back. I'd also make sure that the enemy is always facing the player, all right? Usually if we move the enemy like this, he'll be facing the player. But in case the enemy got pushed around by any other enemies, then it'll look weird when the enemy keeps retreating without facing the player in this state. I'll just make sure that the enemy is facing the player at all times. That we just have to rotate the enemy towards the target, right? We can get the rotation for that by calling coton rotation and passing the vector to the target. Okay? So this is the rotation we want to set for the enemy, for facing the player. But I don't want to set it directly. Instead I want to set it smoothly. What I'll do is I call cotonion rotate towards. I'll pass the current rotation of the enemy as the rotation. And the two rotation will be our target rotation. And we can pass a rotation speed over here. So something like 500 should be good for the speed. And we have to multiply it with time delta time, okay? Finally, we have to store the value of this back in transform rotation, okay? If you want, you could set the rotation directly, but this will make it a bit more smoother. All right? And also we have to make sure that this vector doesn't have any y component. Okay, just in case if you are in some kind of slopy terrains, we don't want to rotate the enemy vertically. The rotation should really happen in the horizontal plane. I'll set the codon of this vector to zero, okay? So this will make the enemy retreat back Next, we should stop retreating when the enemy reaches a certain distance from the player, right? So we can retreat until the enemy reaches the circling distance. Circling distance is 3 meters from the player, right? So let me just copy this and create a new variable over here. I'll call this one distance to retreat. I'll keep this one at 3 meters. Once we are three metres away from the player, we have to stop the state. And we have to go back to the combat movement state. Right from here, we have to check the distance between the player and the enemy. Let me do that. If that distance is greater than or equal to the distance to retreat, then we can go ahead and chain the state back to the combat mid state. I'll call enemy chain state. And I'll pass the Combat Open State. Okay, I'll also return from the execute function so that we won't execute any of this again. Okay, we're done with the implementation of the retreat state. Now we can go to the enemy controller and we can add that state over here. Okay, we also have to store this in our state dictionary. So I'll just duplicate this and change it to retreat after attack state. Okay, so now since we have the retreat state, once we complete the attack, we can switch to the retreating state. Right? So from here I'll switch to the retreat state. When we exit the attack state, we have to make sure to reset the destination of our nav agent, because we're setting the destination from here, right from the exit function of the attack state. I go ahead and reset the destination of the nav agent. So that we can call enemy navigant reset path. Okay, that's all we have to do. Let's go Unity and attach the retreating state to our enemy. I'll do it from inside the prefab. Okay, now the enemy should retreat after attacking the player. So let me go ahead and test that. Okay, yeah, after attacking the player, you can see that the enemy retreated. And it gave a chance for the other enemy to come and attack. All right, yeah, the enemy will keep attacking us one by 11. Thing I don't like here is after the attack, there's a little bit of jitter in the animation before going to the retreat state. This is happening because we are setting the animator parameters like forward speed and straight speed and all, even while the enemy is attacking, Okay? Attack is an action that uses an animation with root motion. In that case, we should not try to modify the animation like this using our parameters fixes or break into. If the animation has root motion, then we can set the delta position to zero, the velocity and everything we set to this will be zero in that case, okay? So from here I'll check if animator apply root motion is true. If it's true I'll just return zero for the delta position and otherwise I'll return the difference of the transform position and previous position. Okay, so this should fix that jittersue that we have after the attack. So let's go ahead and test this. Okay, so now it looks much better. The enemy is retreating after attack and they're taking turns to hit the player. Okay, I can also try attacking the enemy. Yeah, it's looking pretty. Okay, so I'll stop the video here. Thanks for watching, and I'll see you in the next video. 22. Performing Combos: A phone. In this video, we'll make our enemies perform combo attacks while attacking the player. Right now, when the enemy attacks, he's always performing a single attack that doesn't look very good. So we can make our enemies more interesting by making him switch between a single attack and different combos randomly. We'll look at how to do that in this video. So I opened up my attack state and deplement combos. We just have to call the try to attack function multiple times. Right? What I'll do is in this attack function, I'll take an inter parameter called combo count. I'll send it to one by default. After doing the first attack, we should call the tried to attack function again and do a combo. If the compo count is greater than one, right? We could do a four loop from here. Four loop will go from one to the compo count. It'll be less than compo count, I is the index. All right, from the loop we can simply call the try to attack function of the enemy fighter. Okay, But before calling this, we have to make sure that the previous attack is over. We can do that by waiting until the attack state reaches the cool down. All right, cool down is the state from which we want to do the combo. Right, So let me copy this. Wait until coin, I'll change it to cool down. Okay, so we'll wait until the attack goes to the cool down state. And then we'll call the try to attack function again. All right, now all you have to do is pass a combo count to this attack function. And the enemy will perform different combos based on the number passed. Okay, from here, if you pass two, then the enemy will perform a combo with two attacks. And if you pass three, he will perform a combo with three attacks. All right, but we have to make sure that the number of attacks that you pass over here is Leano equal to the number of attacks that the enemy actually has here. We could try to random range function and randomly select a combo con between zero and the number of attacks that the enemy has. Okay, we need access to the attacks list from here. What I'll do is I'll create a property to expose that. Let me create a public property down here. Okay, this has to be attacked data tell, let me change that now. From here we can choose a random number between zero and the number of attacks that the enemy has called. Enemy fighter attacks do count to get the count of the attack. Note that the second parameter in the random dot range function is exclusive. We have to do a plus one over here. All right, now the enemy should perform combo attacks randomly. So it's core humanity. And try to distinguish. All right, you can see that the enemy is performing combos randomly. You could add lots of different attacks for the enemy. And making perform different combos. But for the purpose of this course I'll just use these two simple animations. Because I want to make sure that I'm only using free resources in this course. But you can go ahead and get better animations and create good combos for your enemies. You can always create different combos for different types of enemies and all that. All right, I'll start the video here. Thanks a lot for watching and I'll see you the next video. 23. Counter Attacks: N. In this video we will implement counterattacks. It's going to look like pi. Let's start implementing it. First we need to find the animations for the counterattack. I'll find some animations for that. From Miximo counterattacks, we need two animations, one for the attacker and one for the victim. These are the two animations that I'm going to use. You can just search for assassination and you'll find these. By the way, these are not the best animations for counterattacks. There are much better animations in the asset store that looks more like a counterattack. But I'm just going to go with this because in this course, I really want to use free assets so that you guys can follow along without spending any extra money. I'm just going to go with this animation. Go ahead and download these two animations. I have already downloaded it. Let me go ahead and import it into Unity. These are the two animations, Brutal Assassination and Brutal Assassination Victim. So first we have to rig it. All right, so let me do that now. We should be able to preview the animation. Okay, in this animation, the player takes a few steps before actually performing the attack, right? But we don't want that for our counterattack. We'll be countering the enemy's attack while the enemy is close to the player. We don't want the player to move forward like this. I'll actually start somewhere around here. Frame 21. Let me change the start to 21 and hit Apply. We'll also have to make that change for the victim's animation. Both these animations are synced and they have the same number of frames. Let me also change this to 21. Now. Let me go back to the assassination animation. Yeah, this is how it looks here. I'll chain the based upon of the rotation to original, transform y to feet, transform exit to original. Actually, the original root position is not correct. You can see that the root is over here and the player is over here. We might have to keep this at the center of mass. That will be better. Okay, here I'll check baking pose for position because we have a loop match. And I'll hit Apply. Okay, so next let's look at the victim's animation here. I'll change root transform rotation to original y, defeat and exit to original. The original root transform is correct. In this case both original and central mass doesn't make much difference. So we can choose whatever we want. All right, let me hit Apply. We have set up both animations that we need for counterattack. Let's go ahead and add it to our animator controller. We have to add it to the our right layer. Let me just copy these two. All right, we have to make a transition from the brutal assassination of the attacker back to empty state. Since we want the player to go back to the idle state after the attack. Here, let me just change the name of this to something more simple like counterattack. I'll change this one to counterattack victim. Okay, in the case of victims animation, we don't want to go back to the empty state because once the player does the counterattack on the victim, the victim will die. And the victim should stay in this animation like this. And should not go back to the idle state, right? We don't have to make a transition back to the empty state for the victim's animation. All right, so now we have the animations for the counterattack. Let's go ahead and implement it first. Let me explain how we're going to implement it. While an enemy is attacking the player. There'll be a short window in which the player can counter that attack with M deadlier attack. All right, that's how we're going to implement it. Let's go to the compact controller. Stripped from here. When the player presses the attack button, we have to check if any enemies are currently attacking the player and if that attack is in a window in which the player can counter. Right, If that two conditions are true, then we have to perform the counterattack instead of performing the normal attack right from here. First we have to find if any of the enemies are currently attacking the player. We have list of all the enemies in range inside the enemy manager. From here, we can create a function to get the enemy that's currently attacking the player. I'll call this function attacking enemy. From here, we can just return an enemy from the enemy range that is in the attacking state. Right? We can just use the first function to return the first enemy that is in the attacking state. To check the state, I'll state function of the enemy controller and I'll check if the enemy is in the attacking state, okay? So the first function will return the first enemy that satisfies this condition. But I don't want to use the first function here, instead I want to use first default. The reason is because if there are no enemies that satisfies this condition, then the first function will throw an exception, okay? So we don't want that first default function, we'll just return null if there are no enemies that satisfies this condition. This is what you want to use because we might not have an attacking enemy at all times. All right, so let's go ahead and return this from this function. All right, now back in our combat controller, we can call enemy manager instance, get attacking enemy function to get the attacking enemy. I'll just stow this in a variable. If the enemy is not equal to order. If there is an attacking enemy, then we also have to check if that attack is in a window at which the player can counter. Right, How can you define this window? There are multiple ways to do that in the attack scriptable object. You could define a start and end time for the counterattack window, just like we did for the impact window. That's one way. But if we do that again, we'll have to go through all the attacks and find the counterattack window for each one of them. To keep things simple, what I'll do is I'll make the wind up state of the attack. I'll make the wind up state of the attack the window in which it can be countered. Okay, while the enemy is attacking us. And if the enemy's attack is in the wind up state, then we'll be able to counter that attack. Once the attack is in the impact state, we should not be able to counter it. Right? That look really weird. But during the wind up state, we should be able to counter that attack. All right, this usually works well for me. If you want, you can go ahead and specify a counter window for each attack that will also work. I'm just going to use the wind up state as the counter window. In the male fighter, I'll create a new property called Is counter. Okay, so slur true if the attack state is in a window, that can be countered. In our case, that window is the wind up of the attack from here, we have to check if the attack state is equal to wind up. All right, and we have to check one more thing. We also have to check if the combo count is zero, okay? The reason for this is because since our enemy can perform combos, we should not be able to counter the second or third attacks from the combo, right? We should only be able to counter the first attack. That's the reason why I'm adding this. All right, now back in the combat controller, if there is an attacking enemy, then we can also check if that enemy is in a counterable state. We have to get the fighter from the enemy and then use the counterable property. If both these conditions are true, if the player is not currently performing any other action, then we can go ahead and perform the counterattack. Right, To check if the player is not currently in any other action, I'll just use the merely fighter inaction function. All right, all these conditions are true. We can perform the counterattack, otherwise we can just perform the normal attack. Okay, from here we have to perform the counterattack. I'll create a function for that. In the male fighter, the function for performing counterattacks will be similar to the play it reaction function. We'll have to play an animation and we'll have to wait for it to complete. And all that what I'll do is I'll just make a copy of this function. Then I'll just rename it to perform counterattack. Okay, this function will also take the enemy on which we have to perform the counter attack. So I'll just call this the opponent. And from this function on the player, we have to perform the counterattack animation on the enemy. We have to perform the counterattack victim animation. Okay, let me just copy this function to save time, I'll play the counterattack victim animation on the enemy. All right, after that, the scot will wait for the animation to complete and at the end we'll set the inaction to false. There are some more cases that we have to handle here. While performing the counterattack, we'll start performing the counterattack while the enemy is in the wind up state, right? If we perform the counterattack then we should not continue the execution of the sloop. And we should not go to the states like impact or cool down, right? We have to stop it from here itself. To achieve that, what I'll do is over here I'll create a public property called in counter. Okay. It'll be false by default. And if the encounter is true while we are in the wind up state, then we should just break the loop. We should not continue this attack right from the performed counter attack function. I'll set the counter property of the enemy to drew. We can also set that property for the player. We'll need it in the future while the enemy is deciding to attack the player. It'll be good to know if the player is already in a counterattack or not. Yeah, this will also be useful for the player. Once we are done playing the animation, we can set both of these to faults. Okay, so next, once we perform the counter attack, the enemy should be dead, right? So the enemy should not be able to perform other behaviors like attack or combat movement once the enemy is dead, after the counterattack. Okay, so what we can do is we can create a dead state and we can switch to that state when a counter attack is performed. Let me go here, inside the enemy, inside the state's folder. I'll go ahead and create a new script called Dead State. All right, this will be a state of enemy control. All right, from here let me override the enter function. When we are in the dead state, we can go ahead and remove the enemy from the enemies in range list. If we don't do that, then we might choose this enemy again for performing the attack. Let's go ahead and remove it from the enemies in range list. We can use the remove in range public function for that. All right, from here I'll call enemy manager, instance enemy in range for the enemy. I'll just pass the owner on the enemy of the state. Right? Apart from removing the enemy from the enemy manager, we also have to disable the vision sensor of the enemy, right? If the vision sensor is active, then this will be triggered again and the enemy will be added to the enemy manager's list. Once again, we don't want that, we have to disable the vision sensor. Let's go ahead and do it from the death state. We don't have a reference to the vision sensor yet in the NB controller. Let's go ahead and create that. I'll just duplicate this and I'll create a property for the vision sensor. Okay, I'll make the setter of this public. I'll be setting the reference from the vision sensor itself because in the vision sensor we already have a reference to the enemy controller. We don't have to get it by using the get competent in children function. We can just assign it from here itself. Okay, assign it from the awake function. Okay, so here I'll say vision sensor equal to this. Now we should be able to access the vision sensor from here. And we can disable the game object to which the vision sensor is attached. Okay, remember the vision sensor is not directly attached to the enemy. It's attached to a child object of the enemy. We can go ahead and disable this object entirely. All right, we have created the death state, now we have to add it to the state's dictionary. Let me go ahead and create an enema over here. I'll just duplicate this and I'll cache the dead state. Okay, so now then we perform the counter attack. We can also change the state of the enemy to dead. Let me go ahead and do that. I'll call it changed state and I'll pass the dead state. Okay, so let's strike. Calling this function from the combat controller to perform the counterattack first we have to make this function public. Then I'll call it from the combat controller. Since it's corotine, we'll have to put it inside start. Corotinei'll call male fighter, perform counterattack for the enemy. I'll pass the enemy that's attacking us. Okay, let's go to you and try testing this to attach the dead state to our enemy. And now let's run the game. Okay, let me see if I can counter an attack. Okay, I'm able to counter the attack, but you can see a lot of weird stuff happening. We have few issues here. The first issue is, while performing the counter attack, the enemy and player are facing in different directions. So we have to rotate the enemy and player so that they're facing each other. The second issue is even after the enemy is dead, he's still circling around the player. That should not happen because we did change the state to dead, but something else is changing that state. Let's look at how to fix both issues. First, let's rotate the player and enemy and make them face each other during the counter attack. To do that, we can just find the from the p to the enemy and make the player face in the direction of the vector. First, let the vector from p to the enemy by subtracting the player's position from the enemy's position. Okay, I'll just throw this vector inevitable called displacement vector. Dis vector for shot we want the rotation to be in the horizontal plane. We don't want any value in the y axis. Now we can just set the rotation of the player in the direction of the vector. I just use cotton rotation for that, okay? And we can also set the rotation of the enemy to be the negative of the displacing vector. Okay, so again, I'll use cotton, do look rotation and I'll pass the negative of displacing vector for the enemy. Okay, so this should fix our issue. The next issue is the enemy is still moving around after he's dead. Here we are, changing the state to dead, right? The enemy shouldn't be able to move around. But the problem is, in our attack state for attack, we actually have a cotine, right? We're waiting for the attack to complete and then switching the state to retreat. The problem is this code will execute even if the enemy is dead, right? We don't want that. We can say the enemy should only retreat if the enemy is not in the dead state. And if the enemy is still in the attack state. Okay, if we switched the attack state to something else, then we don't want to change the state from here. From here, I'll check the current state of the enemy attack itself. Only then we should change the state to retreat after attack. All right, so this should fix that issue. Now let's test the game and see if those issues are fixed. All right, let me try to counter. All right, so now we can see that while performing the counter, the player and enemy was facing each other. That looks much better. But there's still one issue that we have. The enemy is falling to the wrong side. The enemy should fall towards the right and not to the left. We can just fix that by mirroring the counter attack animation of the victim. Let me try that again. Okay, let me try to perform another counterattack. All right, so now the enemy is falling to the right side. Okay, so that issue is fixed. We have another issue here. The player is going through the enemy. While performing the counterattack, the player is behind the enemy. This is surely happens sometimes, but we need to fix that. The reason why this issue is happening is because in the initial frames of the counterattack animation, the player is taking a large step and the player is moving forward by some distance While the enemy is attacking, the enemy is already close to the player. When the player moves the distance, the player will move through the enemy and go behind him. Okay, but why is this issue not happening always? The reason for that is because both the player and enemy has character controller on them. In most cases, when the player tries to move forward like that, the character controller will block it. But in some cases it might slide through. We can't really depend upon the character controller. Instead, we'll have to remove this root motion at the start. We'll have to set the position of the player manually so that the player is right in front of the enemy and it looks good while performing the counterattack. Okay. From here. When performing the counter attack, we don't want the player to have root motion. But the problem is if we set the root motion to falls from here using the applied root motion property of the animator, then the player will not also rotate while performing the counterattack. We don't want that, it'll look really weird without the rotation. In this case. We want the root motion to control the rotation of the player, but we don't want the root motion to change the player's position. Okay. How can we achieve that? We can do that by using the on animator move function. I'll actually create that function in the combat controller. If we do it in the merely fighter, then it will also affect the enemy. In this case, you only want to affect the player. I'll create it inside the compact controller of the player. Here I'll define the on animator more function. When we define this function, what will happen is the animator will no longer apply the root motion to the character. And we'll have to apply the root motion manually from this function. Okay. So the benefit of applying the throat motion manually is that we can apply the position and rotation of the throat motion separately. In some cases, we can apply the rotation of the throat motion and not apply the position of the throat motion. All right, so we'll have to manually apply the root motion from here. By the way, if you go to Unity and select the player here in the applied root motion property of the animator, you can see that it is handled by script. Okay? That's because we have to find this animator move function. Now, the root motion will be completely applied from this function. From here, we can decide whether to apply the root motion or not. We can get the root motion from the animator. Let me catch a reference to the animator first. All right, I'll catch it from the function. And now we can get the root motion from animated delta position and delta rotation. Okay? And we can apply them separately. If you want to assign the position of the root motion, then we just have to add it to transform position. All right, If you want to apply the rotation of the root motion, then we have to multiply it with the transformed rotation. I multiply it with delta rotation, okay? So this is the position and rotation that the player moved in the last frame of the animation. Okay, Now we're applying both the position and rotation of the animation. Now this will be just like before, where the root motion is turned on. What we ought to do while the player is performing the counter, we only want to apply the root rotation. And we don't want to apply the root position, right? We want to position the player manually for the counter attack. We don't want the animation to control it. What we can do is we can use the counter function of the male fighter. We can say the road position should only be applied if the player is not in the counter. Okay, now when the player is performing a counterattack, we'll apply the position of the rot motion. We'll apply the rotation right position. We have to set manually, we can just set the player around 1 meter from the enemy while performing the counterattack. To get that position, what I'll do is I'll take the position of the enemy. Then I'll subtract this displacement vector and multiply it with the value that I want. Okay, so here I'll just take the normalized displacement vector. We can add whatever distance you want. If you want the player to be two metres away, we can add two over here. But for this attack, I'll just place the player 1 meter away from the enemy. This will be the target position of the player. We can set this directly to the player's position if you want. But it will be better to set it smoothly while we're playing the counterattack animation. While this animation is being played, we have to smoothly move the player to the target position to do something else. While the animation is being played, we can use a wire loop to wait for the animation to complete instead of using this function, just like we did while we were waiting for the attack, right, So let me just copy these two lines here. While performing the counterattack. Instead of waiting for it like this, I'll wait for it by using a y loop. Okay, From the loop I'll wait for a single frame by calling Healer Turner. At the end of the loop, I'll make sure to implement the timer. Okay? Now from here we can do whatever we want and that will happen barely while the animation is being played. All right, to set the position smoothly, we can use vector three. Move towards function. We want more from the current position of the player to the target position where the player should be while performing the counterattack. In the third parameter, we can pass the delta distance by which the player should move in each frame. I'll just use a value like five over here. And I'll multiply it with time delta time. You can always try changing these values. In future, we might organize these and place all these data in theteralized fields and use it to control how counterattacks work. But first, let's complete the implementation of this. I'll use this to move the player smoothly towards the target position. Okay, so now we shouldn't get that issue where the player reaches behind the enemy while performing the counterattack. Let me try testing this. All right, so now you can see that we don't have that issue anymore. One thing I noticed is that the length of the counterattack animation is a bit long right now. That's why the enemy wasn't able to attack the player even after the counterattack animation was over. Let's look at the attack animation again. And here you can see that after the attack is over, we still have a few frames at the end, so we can get rid of that. I'll shorten this to around here, frame 118. So let me just type that as the end frame. Okay? So now it should work better. Okay? You can adjust the distance from 1 meter if you want. That's up to you. And by the way, next we have to fix another issue. If I go and attack from here, you can see that they'll just stand up because they'll try to play the hit reaction. The colliders of the enemy are still enabled even after they're dead. Okay, so in this case we just have to disable the Character controller. And we can also go ahead and disable the nave agent so that it won't block the path of other enemies. We can go ahead and do that from the death state. First I'll disable the nav agent. All right, and then we can disable the character controller. We don't have a reference to the character controller yet, let me go ahead and make that in the enemy controller. I'll just duplicate this and create a property for the character controller. I'll just assign it from the start function. Okay, so now from here we can go ahead and disable the character control also. So now we shouldn't have that issue. All right, so let me test the counterattack. All right, so now both enemies at it. And now if I tried to attack the collider, you can see that we don't have that issue anymore. Next, there's another issue I want to fix right now. After performing the counter attack, the player is going back to the previous rotation in which she was standing right. Let me show it again. Okay, so after the attack, the player will rotate back. And we don't want that. We can just fix that pretty easily. This issue is happening because in player controller we have target rotation. After the attack is over, we will execute the update function again. We'll go back to our target rotation, right? We can fix this issue by setting the target rotation to the player's current rotation whenever we are in action, okay? If inaction is true, I'll set the target rotation to players current rotation. And now we shouldn't have that issue anymore, so let me try testing it again. Oops, I missed it. Okay. Now, after the counter attack, the player is not changing the direction in which she's facing. That issue is fixed. Yeah, now we have a basic version of counterattack working. It's not perfect right now. There are a few improvements that we need to make. For example, the player should not be able to counter when the enemy is attacking from the behind. If we allow that, then the combat will be really easy for the player. We'll be making such improvements in the coming videos. I'll stop the video here. Thanks a lot for watching and I'll see you in the next video. 24. Targeting System: Hey prone. In this video, we'll build a targeting system with which the player can target different enemies like this. Here you can see that if I'm looking at this enemy, then that enemy will be targeted. But if I change my camera direction and look at the other enemy, then that enemy will be targeted. I'll be implementing that in this video before we start implementing the targeting system. First, let me fix an issue that we currently have, the issue. If we approach the enemy from behind, then we'll get an exception. Let me actually place my player behind the enemy and then I can show you the issue. Okay, if I approach the enemy from behind. Yeah, you can see we have a non reference exception. And this is the line that is causing the nonference exception. It's in the attack state. Why are we even going to the attack state? The enemy haven't spotted us yet, right? That's happening from the enemy manager. If there are any enemies in range, then we'll select one of those enemies and we'll make them attack the player, right? We'll do this even if the enemy hasn't spotted us. All right, while selecting the enemy for attack, we can just add a condition and make sure that the enemy spotted the player. Okay, we can check that by checking if there's a target in the enemy controller from here. By selecting the enemy, I'll select the enemy that has a target here. I'll check if the target is not equal to null. This on the first enemy that spotted the player. Okay, since we added this condition, the attacking enemy can be null. Here I'll just write another condition. I'll check attacking enemy is not equal to null. Then I'll try to attack the player. All right, so now that should fix our issue, so let me try to sing it again. Okay, so now we don't have any issues. So now let's start implementing our targeting system. So let me open up my combat controller here. I'll create a vaiable for storing the target enemy. All right, I'll just make this a public variable for now so that we can see the target enemy in the inspector. In future, I'll change this to a property. For the target enemy, we have to choose an enemy in the direction in which the player is looking. Okay, that direction will be the direction from the camera to the player. Let's create a function for getting that direction here. I'll create a public function called Get Targeting Direction. From here, we just have to return the vector between the camera and the player For that. First we need a reference to the camera. I'll just catch the reference from the awake function. We can get the camera from camera main property. From it, we can get the camera controller. I'm just getting the camera controller here since we might need it for something else in the future. We can get things like plan, rotation and all that. So now we can use that to find the direction from the camera to the player. And we can get that by subtracting the position of the player, actually the position of the camera from the position of the player. Okay, let me just show this in avaitble called from camera. In this vector, I'll set the y component to zero because you only want the direction in the exit axis. We don't care about the component. All right, we can just return this vector in its normalized form because you only one direction as well return vector from camera normalized. Okay, so now we have a function to get the direction in which the player is looking. Next we have to find an enemy in that direction. We'll be doing that from the enemy manager. Here we have a list of enemies in range. From here, we could loop through all the enemies in this list and we could find an enemy that is closest to the direction in which we are pointing, okay. How can we find the enemy that is closest to the direction in which we are pointing? Let's figure it out by using a diagram. Let's say this is the player and these are the enemies. Let's say this is the direction in which the player is looking. Okay, from here we want to find the enemy. That is, to this direction we can just extend the direction vector of the player. Then we have to find this distance between the enemy and that vector, right? How can we find that distance? We can use a little bit of trigonometry to achieve it. First, let's draw a vector from the player to the enemy. And let's say the angle between that vector and our direction vector is theta. Then if we split the vector to the enemy into its horizontal and vertical components, biosynta, then the horizontal component will be costa. The vertical component will be sine theta. Okay? In this case, the vertical component will give us the distance to the direction vector, right? These two vectors are same. Vertical component will give us the distance. We can find it by computing sine theta. So let's go ahead and implement this from the code in the enemy manager. I'll create a public function for finding the closest enemy in the direction in which the player is looking. All right, I'll call this Get enemy to player direction. Okay, so compute this firstly needed reference to the player from the script. Let me create a zeralized field reference for that. We can actually get the compact controller because that's the script attached to the player. If you use it, we'll be able to set the target enemy easily. Let's get that with the player. From here I'll call Player Get Targeting Direction function to get the direction in which the player is looking. Let me store this innovatble called targeting direction. Now we have to loop through all the enemies in the enemies in range list and find the enemy that is closest to our targeting direction, right? Let me use a foraged loop to loop through all the enemies. Then to find distance to our targeting direction line, we just have to compute v sine theta. Where is the vector from the player to the enemy. First, let me find the vector from the player to the enemy. We can easily get that by subtracting the player's position from the enemy's position. Okay, let me just throw this innovatible called vector to enemy. Here. We don't need the y component to zero. Now we have to compute the sine theta distance to the targeting direction line will be V. Get that. First we have to find theta, which is the angle between the direction vector and the vector to the enemy. I'll use the angle function to find that angle. Okay, let me just stare this innovatible now. We can find the distance to the targeting direction by computing sine theta. V is the magnitude of the vector to the enemy. Then let me multiply it with set. I'll use math of sine function and I'll pass the angle. One thing you have to remember is we have to pass the angle as radiance to the sine function. So we have to multiply the angle with Matt. Did Dan dicto? Okay, that will give us the distance between the enemy and the targeting direction. Now we have to loop through all the enemies and find the enemy with the least distance to the tagting direction, right? To find that, begin to create two variables here to keep track of the distance the closest. So I'll create in distance and I set it to a really high value, like infinite deep. By default. Then I'll create a bailable to store the closest enemy as it to not by default. Now from here, if the distance that we computed is less than mind distance, then the new mind distance is going to be the distance and the closest enemy is going to be this enemy. Okay? Now by the end of the F loop, we will have the closest enemy in this variable. So we can go ahead and return that from this function. Okay, now from the update function, we can call get closest enemy to play a action and get the closest enemy, and we can save it into the target enemy of the player. Okay, By the way, calling this function every single frame might be a bit expensive because we are calculating the magnitude and all that. To optimize it a bit, we can just make sure that we're only calling it every 0.1 seconds or something that I'll just create a timer over here. I said it is zero by default. I'll keep updating it at the end of the update function. And then if the timer is greater than 0.1 then we can execute this line. And we also have to reset the timer to zero in that case. Okay, I'll just make this greater than equal to, it doesn't really matter, but I just like things to be perfect. Now, this slowly be called. Every 0.1 seconds, it'll find the closest enemy to the direction in which the player is looking. Go to Unity and try testing this. First we have to assign the reference of the player to the enemy manager. We will also make the player a single. Both ways will work. Let me try testing this now. All right, so I'll have to minimize this and select the player to see which enemy is selected. Right now, none of the enemies are selected as a target enemy. But if I move closer and if I look at this enemy, you can see that an enemy is selected here. But if I change my looking direction and look at the other enemy, you can see that the enemy also changes. Okay? So the enemy is changing based on the direction in which we are looking. Our logic is working fine, but we need to provide feedback to the player to understand which enemy he's looking. The player can't look at the inspector, right. To do that, we could just highlight the enemy that the player is looking by just giving a little bit of glow like this. It's a common thing that you'll see in games like Assassin Three. Let's go ahead and implement that. To make our enemy glow. We could just create a simple shader for those who don't know what a shader is. A shader is a program that determines how things should be rendered on the scene. If a thing that you see in the scene right now, they have a shader and the shader is deciding how it should be rendered. It's really useful if you want to add a visual effect on like a glow or transparency or anything. Let's go ahead and make a shader for making our enemies glow the acts. I'll create a new folder called shaders. Okay, here I'll create a new shader. Let me go to Create Shader Universal Under Pipe Plan, because that's the pipe plan you're using for this project. From here I'll select shade graph. Okay, I'll call this highlight shader. We'll be creating our shader by using the stool shader graph. I'm not going to go and explain the basics of shader graph and all that. That's not the focus of this course. There are many courses in free tutorial is that are dedicated to shaders. You can go ahead and check them out. In this video, I'll be just creating this simple shader and I'll also make the completed shader available for download in case you don't want to create it on your own and just want to import and use it in your project. Let me go ahead and create this shader. First, we want to add a texture because our enemies have a texture. Right, this is a texture used by the enemy model. Before implementing the glow and all that, first let's add the texture. Click on this plus button and I'll add a new texture to the, I'll just call this texture. We can just plug it into the base color of our shader. We can't plug it directly because the base color has to be an RGB value. We just have to pass it through sample texture node to convert it into RGB. By the way, what I'm doing here is I'm clicking on the sport of this node. I'm dragging, this will give us a list of nodes to which this texture can be connected. Okay, from here we can search for sample textuuy it'll give us a sample text node. If you click on that, it'll create that node and create a connection to that node. Okay, let me just minimize this and the RGBA value into our base color. All right, now we have created a basic shader that will just show the texture, but in the shader we also want to add a little bit of glow for highlighting the enemy, right. To do that we can use the emission property of the shader to them. We can just pass, I'm pressing Space button here and it'll keep me the list of nodes. From here I can search for feral effect. Okay. This is an effect that is commonly used for glow in the center, it'll be black and towards the edges it'll be white. We can also change it by playing with the power. All right, we'll connect this to the emission property here. We can also create a variable so that we can control it from the meal. It's just like exposing available in the inspector here. I'll create a float variable and I'll call this glow power. Let me just drag and drop the variable over here. I'll attach it to the power. Everything has became white. So that's because the default value of this variable is zero. So we can change it to something like one or two by default. Okay, here we have our chat. Now let me go ahead and save this by clicking on the Save Asset function. And I'll use Shift space to go out of full stream. Okay, so here we have a shader. So now we can use the shader to create a material that we can attach to our enemy that I'll right click on the shader. Okay, I'm not right clicking here, I'm clicking on the shader. And then I'll go ahead and create a new material. Okay, I'll just call this highlight material. Put the texture, I'll just search for paladin texture and this will give us the textures of our enemy here, The diffuse is the one that we want to use because that's the one with the color. Okay, let me put this material in our Materials folder, Now we can try attaching it to our enemy. Let me go inside the prefab and let me find the object with the mesh. Actually, for this enemy, we have two objects, one for the body and one for the head. But for some reason the naming is given by the mix is wrong, it doesn't really matter. What matters is we have to apply the highlighting material for these two game objects. If you look at the skin measure under Property of the object here, you can see this is the material that it's currently using right now, so we could replace it with our highlighting material. You can see that we have a white color at the edges which makes it seems like the enemy is glowing. Okay, We also have to do it for the helmet of the enemy. Let me also change that, and by the way, I'm just trying this out. We don't want the enemy to have this material. By default, we'll have to dynamically switch the material from the script. Okay, so this is how the enemy will look. Now let me switch back the materials to the old material, which I believe is pain material. We have to switch the material dynamically when an enemy is being targeted. Right, so let's go ahead and implement that in our Util folder. I'll create a script for changing the material of a skinned mesh. So I'll call this skinned mesh highlighter. All right, in the script. Silky debatable for storing the meshes that we need to highlight. All right, so this will be a list of skinned meshrenderka. This is Vicus. The enemy is rendered by using a skinned meshnder. Right? If you were trying to highlight a simple object like a cube or spear, then we can't use this because it will be a mestrendera and not a skinned metrederka. So I'll just call this one meshes to highlight. Okay, next I'll create two variables for storing the original material and the highlighted material for the mesh. So fast I'll create a material called original material and then I'll create one for the highlighted material. Okay. I'll create a public function here called highlight mesh. And still take a bulling so that we can specify to highlight or unhighlight the mesh. Okay? And from this function we have to look through all the meshes in the list. All right? And for each mesh we have to change the material according to the value of the highlight pulling. If highlight is true, then we have to use the highlighted material. Otherwise you can just use the original material. Okay, this is all going to do from the script. Now let's go Unity and attach it to our enemy. I'll go inside the prefab and I'll attach the skin mesh highlighter. Next we have to assign all these fields, these two other Me objects that we need to highlight. Right, let me draw and drop them to our meshes to highlight list. All right, then we have to assign the original and highlighted material to the original material is met. The highlighted material is called highlighted material. Let me also assign that. Yeah, now we have a script with which we can switch the material of the enemy and highlight the enemy first, let me create a reference to the highlight in the enemy controller. So I'll just duplicate this and I'll create an instance of the higher. Okay, we have to catch it from the start function. Now we can use it to highlight the enemy from the enemy manager. Whenever we change, whenever we set the target enemy, we also have to highlight that enemy. Right? What I'll do is I'll just throw this in another table called enemy. We only have to do the highlighting. The closest enemy and our current target enemy are different. So fail if the enemy is not equal to all, if the closest enemy is not equal to the enemy that we're currently targeting. Okay, if those two conditions are true, that means our target has changed, so we have to change it in the player target enemy, okay? And we also have to highlight the target enemy. To do that, we can call player dot target, enemy. Match highlighter. Highlight match function. Okay, And here I'll pass through because we want to highlight it. Along with this, we also have to unhighlight the enemy that was previously highlighted. Right before we change the target enemy, Let me show the previously highlighted enemy in another variable. All right, now from here we can just un highlight that enemy. I'll just duplicate this line to save time. Okay, So this will highlight the previous enemy. Just to be safe, I'll just add an unconditional operator everywhere. Let me also add it over here, because just in case, if a highlighter is not attached to an enemy, the whole thing should not break. Right Now, let's go Unity and test if everything is working okay. Yeah, if I go close to an enemy, you can see that that enemy is highlighted. And let me look at the other enemy. Yeah, now you can see that the other enemy is highlighted. All right, that looks fine. We are highlighting the enemy that is closest to the direction in which we are looking. Okay, by the way, if you want, we can also change the power of the globe if you want the highlighting to be more prominent. Let me just materials and find the highlighting material. We can reduce this to something like 1.5 That should increase the glow. Reducing this value will be increasing the glow. You can see it happening. I'll sit it to something like 1.5 Okay, let's maximize this. Say this looks fine to me. We have built a system for targeting different enemies. This will also work while we are in the combat. All right, I'll stop the video here. In the coming videos, we'll be looking at how to make the player attack the enemy that's currently being targeted. And we'll also make the player face the targeted enemy while in combat. I'll be stopping the video here. Thanks a lot for watching and I'll see you in the next video. 25. Lock On Combat Mode: One. In this video, we'll implement the lock on mode or the combat mode. For the player. The player will be able to target an enemy and go to the lock on mode. And once the player is in the lock on mode, she'll always be facing the target enemy while she's moving. Okay, if we move the player towards the site while she's in lock on, then she won't walk normally. Instead she'll while looking at the target enemy. Other than that, we'll also be fixing a couple of bucks in this video. Let's get started. First, before we implement lock on, I want to fix two issues that we have in our game right now. Let me show you the issue first. The first issue is if the enemy attacks while they're chasing, then you can see that they are not playing the animation while retreating after the attack. Okay, this only happens when they chase us and attack. We need to fix that issue. It's happening in the combat open state when the enemy starts, we're setting the combat mode as false. Okay. But we don't have to do this because now since we're using a Blentry for the combat movement, we do have running animation in here, right? While we can use this running animation, we don't have to go out of the combat mode and back to locomotion while chasing. We don't have to set the combat mode to falls when we start chase. Let me remove this line, begin to set it to true when we start the combat movement state itself. I'll move this line to the Enter function of the combat movement state. Okay, and then we can Sid. It falls from the idle state because once we go to the idle state, we don't want the enemy to be in the combat move. All right, so this should fix issue, so let's try testing it. Okay, so now we don't have that issue. The enemy is playing the walk back animation correctly while retreating. That issue is fixed. There is another issue that we have, the issue. If we kill the enemy that is being currently targeted, then you can see that that enemy is still being highlighted. Okay, once an enemy dies, that enemy should no longer be the target enemy of the player right? Now if you look at the inspector, you can see that that enemy is still the target enemy right. Now when we implement lock on, the player will still keep locking onto the enemy even after he's dead. We have to fix that if a target enemy is dead, then we have to reset the target enemy. Let's do that. We can actually do this whenever we remove an enemy from the enemies in range. Okay, so we might remove the enemy when the enemy dies, or we might even remove the enemy when the enemy is far away from the player. Right? In both cases we don't want the enemy to be the target enemy from here. After removing the enemy from the enemies in range list, we can also highlight the enemy from here. I'll call my highlighter to highlight mesh and pass falls to highlight the enemy. We really need to do this if the enemy that's being removed is the target enemy. Let me check that here. Okay, so if the enemy that's being removed is the target enemy, then first we'll unhighlight the enemy. And then we also have to change the target enemy. Right, I'll the target enemy as the closest enemy in the player's direction. Let me call get closest enemy to player direction function. Okay, so this will reset the target enemy. If there are no other enemies in the enemy's in range list, then the target enemy will be set to nor. In both cases, we'll change the target enemy from the enemy that's being removed. Okay? After changing the target enemy, we can go ahead and highlight it. Okay? So here you have to use the unconditional operator because in some cases there might not be any other enemies close to the player, and in that case, the target enemy will be null. If you don't use unconditional operator, then you'll get an exception here, okay? So let me go ahead and highlight the new target enemy. Okay? So now once an enemy is dead, he should no longer be targeted. So let me try testing it and let me kill these two enemies really quick. Okay, All right, so now we can see that once the enemy is, we are no longer targeting that enemy. All right, that issue is fixed. Now we can go ahead and implement the lock on mode or the combat mode for the player. First, I want to improve the walking and running animation that you're playing while we're in the combat mode. If you go to the combat move, bluntree, you can see that for the walking and running animation we're playing, playing, walking and running animation. Right? It would be better to have an animation in which the player is walking and running with a sword. Okay, just like our walk back animation here, the player is actually holding a sword and that looks much better. All right, let's find some animations for that. I'll go to Miximo. In the animations, I'll search for sword and shield walk. Okay, so here we have an animation where the player walks with the sword. So I have to check in place for this because we don't want the root motion of the animation. Okay, so go ahead and download this animation. I have already downloaded it. Next I'll search for sword and shield run to find the run animation. Okay, so this is the animation I'm going to use for the run. Again, you have to check the in place check box before downloading it. All right, so go ahead and download these two animations. I have already downloaded it. Let me mote them into my animation folder. These are the two animations. I'll dragon wrap them into the combat animations folder. First we have to rig these two animations. Okay, so let me make it humanoid. I'll choose the Erica Ava. All right, Now I should be able to review the animation. We want this animation loop. So I'll turn on loop time and loopholes. I'll chain the root transform rotation to original, root transform position to feet transform position, exit to original. Then I'll check bake into pose for all the three root transforms because they have loop match. Okay, So this is how the animation will look like next. Let me do the same for the run animation. First Elton on loop time and loopholes. Okay? And then I'll set the based upon for all three transforms and then I'll check bake, interpose for all the three transforms. Okay? This is how the Ron animation will look like. Let's replace the old walk and run animation with these two animations. Okay? This is the walk animation. I'll replace it with the new sword and shield walk animation. And this is the run animation. So I'll replace it with sword, shield, run. All right, so now the player should walk and run while holding a sword. Okay, that look much better than the previous walk in run animations when we are in the combat mode. Okay, Next we should implement the code for making the player go to the combat mode. So the player can go to the combat mode in two ways. The first pay, the player can press the lock on input to lock onto an enemy and go to the combat mode. And second, when the player attacks an enemy, we can lock onto the enemy and go to the combat mode. Okay. So the player should be able to do it manually by pressing the lock on input. And we should also automatically go to the combat more when the player attacks an enemy, Right? First, let me define an input for the lock on. I'll go to the input manager in here. I'll just replicate this jump input and create a new input for the lock. Let me name lock on for the button. I'll just give the key on the keypoart. We also have to define this input for the joystick, but I'll be doing that later because for the joystick I want to use the right trigger. Using the trigger as a button is a bit more complex. I'll be covering that later. First, let's actually implement the lock on for the player. I'll go to the combat controller script from here. When the player presses the lock on input, we have to go to the combat mode. First I'll create a property for the combat mode. All right, I'll create a Bolling property called combat. I want to implement this in such a way that when we set the value of the combat mode property, we also have to set that value in the combat mode parameter of our animator. All right, when we set this property, we also have to set that value to the animators parameter. We can do that from the sector of the property when we're setting the property. We can also set the animator parameter. All right, to be able to do that, we can't just define the property like this. This is actually a short way of defining a property. It is called auto implemented properties in C Sharp. Okay, You can check the documentation. We can also define the properties like this, in which we can implement the getter and sector of the property. When we implement the getter and sector, we'll also be able to do other things when the value of the property is set, okay? So we can't define the property like this. This is a short form for defining the property, so we'll have to define the property in its long form itself for that. First I'll create a private pooling variable called Combat mode. All right, here the C is lower case. Then I'll create a public property Combat Mode with a upper case. Okay. And in this property I'll implement the getter and setter. In the getter we just have to return the combat mode private Viper. Okay. There are different ways to write the get. You could write using a curly brasis like this and then just return the combat mode Viper. All right, but since this getter only has a single line, we could simply use a lambda like this. We don't have to write braces or anything. Okay, next let's define the setter. Again. For the setter, we can define it like this using a lambda function. In the case of the setter, we have to set the value to the combat mode variable. The value will be the value that is set onto this property, okay? So we could define the setter like this if we only had a single line. But in our case, we also want to set the animator parameter when we are setting the property's value, right? So I'll use a curly base because we'll have multiple lines in the setter, okay? And from here first I'll set the combat mode variable to the value that is set to the property. This is same as this, okay? This is the actual way of defining a property with the getter and setter. And this is just a short way of writing this. When we write the property in the short way behind the scenes, C sharp will define a private variable like this and define getters and setters for it. Okay? In this case we can't use the short definition. We'll have to use the actual definition of the property from here, from the set, whenever we're setting the value of the combat mode, we should also set the animator parameter. Right from here I'll call animated dot sit bool. And I'll sit the value of the combat more to the value that was currently set to the property, okay? So now, whenever we set the value of this property, the property will automatically set that same value to the animator parameter, okay? And from here we could also add more checks. So for example, when we don't have a target enemy, we should not be able to go to the combat mode. Right from here, we could just check if the target enemy is null. If the target enemy is null, we should not be able to go to the combat mode. So we can just set the combat mode as false. All right, so yeah, this is the power of using properties. We can add any number of statements in the getter and setter and we can execute additional logic when we get set the value of a property. Okay, so now we have the property for the combat more. Next we should change the value of this property when the player presses the lock on input. Right from here I'll check if the lock on input is pressed. All right, and if the lock on input is pressed, then we have to reverse the value of the combat mode, right, when they are not in the combat mode. And when we press the lock on input, we have to go to the combat more. And then when we are in the combat mode and if the lock input is pressed, then we have to go out of the combat mode. Okay, from here we just have to reverse the value of the combat mode. Like this, it will automatically do checks like this to make sure that we won't go to the combat mode without a target enemy. And it will also set the same value in the animator. All right, using a property like this will allow us to make our code a lot cleaner and shorter. We don't have to execute those additional logic from here, from wherever we set the property. Next, when the player performs an attack, we have to go to the combat mode. Right from here I'll just set the combat mode to true. All right, again, even though we're setting it to true from here, it'll only be set if there's a target enemy. All right, next, when we are in the combat mode, the target enemy of the player can become right. For example, when the target enemy dies or when the target enemy goes out of the range, we'll see the target enemy as nu. In that case, we should change the combat mode back to false. Otherwise, the player will be locking on to the dead enemy when we set the target enemy to Nor, we have to set combat mode to false. Again, for doing that, we can use the setter of the property. First, let me turn this into a property. I'll rename this to have a upper case, because the properties should start with an upper case, right? And then we can define the getter and setter. We also have to define a private variable for the target enemy, right? And from the getter we can return that target enemy Come from the setter, we can set the value of the target enemy, private viber. Then if the target enemy is, then perhaps set the combat mode to false. Right, we can't be in the combat mode if there is no target enemy. Okay. So we have implemented the logic for setting and resetting the combat mode, right Next we should implement the logic for how the player should behave when he's in the combat mode. Okay, so we'll be doing that from the player controller. From here in the player controller, right. Now we're just rotating the player to the direction in which she's moving, right? But when we are in the combat, we should not do that. The player should always rotate towards the target enemy, right? Also when we are in the combat more, we should split our velocity into forward and sideboard component and set it to both forward, speed and speed. In the combat mode, the player will always be facing the target enemy. The player will be strafing around the target enemy. We have to change this implementation from here. I'll check if we are in the combat mode. And by the way, to access the combat mode property, we need a reference to the combat control from the player controller. Let me go ahead and cache a reference to the combat controller from the awake function. Okay, now from here we can check if we are in the combat mode. If you are in the combat mode, we have to use a different logic for updating and animating the player. Otherwise, if you're not in the combat mode, we can use our old logic. So I'll just copy these lines and paste it over here. All right, so if you are in the combat mode, I don't want the player to be able to run. Okay, I'm designing this combat system similar to the combat system from the assassin street games. While you are in the combat mode, we won't be able to run. We'll only be able to walk. And if you won't run, then we have to plus the lock on input again to go out to the combat mode and then we'll be able to run away from the enemy. Okay, that's how I'm going to implement this combat system. We won't be able to run while we are in the combat mode. While we are in the combat mode, what I'll do is I'll divide the velocity by four, okay? This will reduce the speed in which we can move while we are in the combat mode. All right, then while we are in the combat mode, the player should always rotate and face towards the target enemy. Right, then for setting the animation, we should split the velocity into its forward and sideward component. And we should set it into the forward speed and stray speed. Right, the player should also be able to Sra when we are in the combat mode. Okay, we have to do these two things from the combat mode. And by the way, I'll move the character controller function to the end because we are modifying the velocity from here, right? I'll also move the line where we're setting the speed for the gravity here. When we are modifying the velocity, we should not modify the speed because this is purely controlled by the gravity. It's not controlled by the player's input, right? The gravity should not change when we are in the combat modest it from here. All right, next we have to rotate the player towards the target enemy. For that first I'll find the vector from the player to the target enemy. We can find that by subtracting the position of the player from the position of the target enemy. Okay, let me just toll this innovable called target vector. I'll set the y value of the target vector to zero because we only want to rotate the player in the horizontal plane. All right, then from the target vector, I'll find the target rotation by using the cotton rotation function, just like we're doing here. Let me just copy this line. Okay, by the way, I really do this, if the player is moving right, visually change the rotation when the player is moving. And after finding the target rotation, we can just rotate the player towards the target rotation by using the rotate towards function, just like we're doing it from here. So I'll just copy this line and base it here. All right here. We could use a different rotation speed if you want while we are in the combat part. But I'll just keep it as the same for now. And I'll see how it looks. Okay. This will make sure to rotate the player towards the target enemy when we are in the combat. Next we have to split the velocity and set it into the forward and speed. We have already done this for the enemy. If you look at the update function of the enemy controller here, you're splitting the velocity into forward and the sideward component. And we're setting it to the forward speed and straight speed. Right, we can do the same thing from the player controller while the player is in the combat mode. I'll just copy these lines and I'll paste it in the player controller. Okay, so here we have here, our animator is not a property, it's available. So I'll change the first letter to lower case. Then here for the speed we have to use the most speed. All right, now all the errors are fixed and we are splitting the velocity and setting it to the forward speed and the straight speed. All right, by the way, I just noticed that I forgot to change the mode direction to target vector here by copying and pasting this line. Okay, let me also change that. When the player is in the combat mode, we are handling the rotation and animation differently. Let's go to it and try testing this. Let me go near an enemy to take the enemy and I'll press the key to lock onto the enemy and go to the target mode. Here you can see that the player is playing the combat idle animation. The player is in the combat mode from here. If we try moving the player, you can see that the player is always facing the enemy. The player is T. Then we move towards the site, right? The player is not just walking forward and rotating towards a more direction like before. Okay, one thing to note here is that the animations might not look good when we move in some directions. The forward, the backward walk, the walk towards the left side and the walk towards the right side will look fine. Okay, But when we try to walk in diagonal directions, it won't look that good. By the way, when I move out of the range will go out of the lock on mode. If I try to move in directions like this, you can see that the animation doesn't look good. All right. The reason for that is because we don't have a dedicated animation for walking in diagonal directions, right? We're just playing a blend of the strafing and walking forward and backward animations. The blend will not look good in some cases it's always best to have diagonal walking animations, but unfortunately, I haven't found any free diagonal walking animations where the player is holding a sword. I think we don't even have any normal diagonal walking animations in Miximo. But if you buy some professional animation pack, you should have diagonal walking animations in it. Since this is, I won't be using any paid animations in it. But I just want to let you know that if you want better diagonal walking animations, you can find them in animation packs like this one by bald. You can add those animations to the bluntre. I can show you an example in which I used a pad animation pack called Swadanimstp by Ubold. In this pack, all the animations are made by using Mocap. And we have animations for diagonal box while holding a sword. This is a project where I use the paid animation pack. Here you can see that the diagonal locking animations look a lot more realistic. There is no foot sliding Synthia using dedicated animations and not a blend between two animations. These are the animations are used for creating this controller. Here you can see that we have a 45 degree animation for the left and right direction. We also have a strafe 135 degree animation for left and right. We have diagonal blocks in all the directions. This is how the Plintree set up. We have all the diagonal walking animations in the Plentree. We can also try testing the Blinreef. I try to play diagonal walking animations from here, you can see that the animation looks really clean. Yeah, I just showed you this in case you wanted to set up your controller with paid animations like this. But I'll only be using free animations in this course. It's going to be okay for the most part, but we might have some food threading issue here and there during diagonal walks. Yeah, just keep that in mind. Now let's get back to testing the combat mode. All right, we can try testing it while we are in the combat. Yeah, it looks pretty fine. We can move around the enemy like we are in the battle. This looks much better than walking normally while we are in combat. I'll stop the video here. The next video, we'll look at how to make the player rotate towards the enemy while performing an attack. Thanks watching, and I'll see you in the next video. 26. Directional Attacks & Rotating while attacking: One. In this video, we'll make some improvements in our compact. First, we'll make our characters rotate towards the attacker while taking a hit. Then we'll also allow our player to attack in different directions. For example, if an enemy is standing behind me, I can just point in that direction and press attack. And then the player will turn and attack. Yeah, let's look at how men this. First I want to make the player face the enemy while the player is taking a hit from the enemy. All right, the enemy should also do the same. They should praise the player while they are taking an attack from the player. So let's go ahead and implement that. I'll go to my male fight descript. This is where we have the code for playing the hit reaction. While we play the hit reaction, we want to rotate the character and face the attacker for that first, we need a reference to the attacker. Right? I'll add a parameter in this function for the attacker. Then before playing the hit reaction, we can make the character face the attacker that first I'll find the vector from the character to the attacker. We can get that by subtracting the character's position from the attackers position. I'll just set the Y of the displacing vector to zero because you only want to rotate it in the horizontal plane. Then to rotate the character, I'll use cotonrotation to get the rotation from the displacing vector. Okay, same thing that we did over here for the counterattack. We're just rotating a character to face the attacker. All right, now from here when we call this function, we also have to pass the attacker. Here we only have the collider that attacked this character. This collider will be the sword. Right From this, we have to get component in parent and get the male fighter to find the character that attacked the player. Okay, this is not really efficient. We'll be improving this in the future. Being the status script to our weapons and cash reference to the mainly fighter in that script. That way people won't have to use get component in parent and it'll be more efficient. We'll be doing that in the future. This is all you have to do to make the character face the attacker during hit reaction. Next one thing I want to do is I want to change how the targeting works while we are in the combat mode. Okay, if you're not in the combat mode, we should target like this by using the direction of the camera. But while you are in the combat mode, I don't want to use the camera for targeting the enemies. Instead I'll just use the forward direction of the player. Okay, so this works really well because when an enemy attacks the player, we will rotate towards our enemy, right? If we set the targeting direction to our forward direction, then we'll automatically target that enemy who attacked us, which is what we want in the combat. All right, from here, if we are not in the combat mode, then we can find the targeting direction like before. Otherwise we can just return the forward direction of the player. Okay, Using the forward direction will be better because a player will rotate the lot while we're in combat. And it's always good to target the enemy that is in front of the player. Let's go to T and try to distinguish. Okay, let me just go to the lock on mode. Yeah, now you can see that when an enemy attacks, we are facing that enemy while playing the hit reaction. Okay, so this can be a bit snappy, but lots of assassin screen games use these techniques where the player will just instantly rotate towards the attacker before taking the hit. Next, I want to be able to attack enemies based on our input direction. Here I was intending to attack the enemy behind me, but the player will always attack in the direction in which she's facing. Right? That's a problem. We won't be able to attack the enemy behind us. Instead of this, we should be able to specify a direction and attack the enemy in that direction. While we are attacking, we want to rotate towards that enemy. Let's go ahead and implement that here in the combat controller. When we perform an attack, we also have to pass the direction in which we want to attack. Okay, So we can get the input direction by multiplying the horizontal and vertical input with the cameras rotation like we do over here, right here we are. Using it to find the direction in which we should move. But this is basically the input direction that the player is giving, right? So we can do the same to find the direction in which you should attack, okay? So we can actually store this in a public property here. Here, I'll create a public property called Intent Direction. I'll call it Input Direction to keep things simple, okay? And I'll just set it from here. Now we should be able to get that direction from here and use it for the direction of our attack. But from here first we need a reference to the player controller. Right? What we can do is we can just make the player controller a singleton, because we have to access it from multiple scripts. Here, let me create a public static instance of the player controller. Then I'll just initialize it from the awake. Now we can access it from the combat controller. From here I'll say player controller instance input direction to get the direction in which we want to attack. Now we're passing the direction to our t to attack function. But this function doesn't take a parameter at the moment. Let's define a parameter here. So I'll call this attack direction. And what I'll do is I'll make this nullable vector and set its default value to null. Okay? The reason for this is because this function is also used by the enemy, right? In case of the enemy, we won't be able to pass the targeting direction or anything. That's only for the player. So this has to be a default parameter and the attacking direction should be ignored by default. Okay, let me also define this parameter in our attack function, and I'll pass it while we're calling the attack function. Okay, so now when we are performing an attack, we should also rotate to the attacking direction. All right, from here first I'll check if the attacking direction is not null. If that's true, then we can use con, rotate towards, we can rotate our character towards the attacking direction. For the from rotation I'll pass the current rotation of the character. We can get the two rotation by using corotation and passing the attack direction. Finally, full speed we can pass something like 500, but I'll just make it a Liz field variable over here instead of just hard coding the rotation speed. All right, so I'll define it over here and I'll set its value to 500 by default. Okay, let me pass it over here. And we also have to multiply it with time delta time. We have an error over here. That's because the attacking direction is nullable vector. But the look, rotation takes a vector, not inullable vector. We can just pass the value of the attacking direction and that issue should be fixed. Okay, now we should rotate towards the attacking direction. We forgot to do one thing. We have to set this rotation back to the rotation of the player. We forgot to do that. Yeah, the rotate the player towards the attacking direction. Third score, unity and protesting this. All right, let me go to the combat mode and let me try attacking this enemy. Yeah, you can see that the player turned and attacked the enemy. Next, we can do another thing to improve our attacks even more from here. Instead of passing the players input directly to the attack function, we can check for the enemy that is closest to this direction. Then we can pass the direction to that enemy. Okay, if we do that, the player will rotate towards the closest enemy and attack the enemy. That will be a bit more accurate than passing the input direction directly simplian that. So in our enemy manager script, we already have a function to get the closest enemy to a direction, right? We can use this function to get the enemy to the input direction. But right now, this function uses the targeting direction, which is not what we want. What we can do is instead of always using the targeting direction from this function, we can take the direction as a parameter. All right, let me just remove this line. Now in here, instead of targeting direction, you have to use direction. I'll also rename this function to get closest enemy to direction. Okay, So now when we call this function, we also have to pass the direction. The direction in this case is the targeting direction of the player. So we can just pass that while calling this function. Okay? It looks like the function's name was not changed because we already had an error here. Just copy paste the name. All right, so now the other should be gone. And I'll also change the name over here. Here we also have to pass the direction as a parameter. Again, I'll use player targeting direction to get the direction. All right, so now we can also re use this function for any direction that you want. From the combat controller, we can call enemy manager instance, get closest enemy to direction for the direction I'll pass, the input direction of the player. Okay, I'll show the result. Innovatible enemy to attack. Then I'll create a nullable vector called direction to attack. This will be noted by default. If we have an enemy to attack, then we can set the direction to a vector to that enemy. Okay? If the enemy to attack is not, then direction to attack will be a vector from the player to the enemy to attack. We can get that by subtracting the position of the player from the position of the enemy to attack. Okay, so we can pass this as the direction for our attack. This will be a bit more accurate. The player will exactly rotate towards closest enemy in our input direction while performing an attack. Okay, let's try testing this. All right, let me go to the combat mode. Yeah, you can see that the player is rotating perfectly. Okay. Now we can perform attacks in different directions and we can target enemies standing around us. All right, so I'll stop the video here. Thanks a lot for watching and I'll see you in the next video. 27. Controller Input Setup for Combat: In this video, we'll set up controller input for our attack. Right now, we don't have a way to attack the enemy or go to the lock on mode from the controller, we'll be implementing that in this video. Adding a controller input for attack will be pretty straightforward. We can just use the joystick button two, which is the X button on the joystick. All right, we already have an input for that called Fire three. We just have to rename that to attack. And now we should be able to attack by using the X button on the joystick. Okay, next I want to be able to do the lock on from the controller. For the lock on, we'll be using the left trigger. That is the input commonly used in games like Assassin Screen. Using the left trigger will be a bit more complex because the left and right triggers of the joystick are axis, they're not buttons. Let's look at how to set it up. Since the left triggers an axis, I'll actually duplicate my vertical axis and create a new one called Lock on Trigger. This is going to be a joystick axis. An axis, I'll choose the ninth axis. Okay, nine taxis is the left trigger and the right trigger is the ten taxis. All right, we have defined the input. Now the challenges. How can we know if the left trigger is down? We can't use the get button down function because the left trigger is not a button. The only thing that we can get is the value, the axis value of the left trigger. All right, if I do this I can get the access value. But the problem is we should not keep changing this if the player holds down the left rigger, right? Instead, we should really change this if the left rigger was pressed in the current frame, right? If we just check something like the value of left trigger is greater than 0.1 or something, then the problem is when we hold it, we'll keep changing the combat mode, We can't do that. Instead we need a function, get button down. Which will only be true if that button was pressed in the current frame. Okay? Unfortunately we don't have a function like that. For axis, we only have button. Let's create that function on our own. I'll create a new helper script for this in the Util. I'll go ahead and create a script called Joystick helper. Okay, here we can create a bulling function called get left trigger down. All right, from here we just to check if the left trigger was pressed in this current frame, right? That means it was not pressed previously but now it is pressed to check if it's currently pressed or not. What we can do is we can check its axis value. Okay, Lucent put, get access draw to get its axis value. The name of the axis is lock on trigger, we can check if its value is greater than 0.1 I also want to take the absolute value of this because we don't care about the sign of this axis, okay? So if the axis value of a lock on trigger is greater than 0.1 that means it is currently pressed. Next, we have to check if it was previously pressed. So we can use a boren variable to store that. I'll create a variable called previously pressed. It'll be false by default and at the end of our function we'll set it to the value of currently pressed. Okay. Now if the left trigger was not previously pressed and if it is currently pressed, then that means the trigger was pressed in this frame. Okay, so we can return true in that case, and otherwise we can just return false. All right. This is all we have to do. This will check if the left trigger was pressed in the current frame. But I want to generalize this so that I can reuse this function for all our axis, like right trigger, the right joystick and all that. Okay, To do that, what we can do is here, I'll just change the name of the function to get axis down. Instead of get left trigger down, I'll take the axis name as a parameter. Okay, here I'll use the axis name. Then we can't just use a single boling variable to check if it's previously pressed. Because now this axis can be any axis in Ojostic, we have to store the value of all those axises instead of this Boolean variable. We can create a dictionary with axis name as a key and boling as the value. I'll just call this axis states. All right, now from here to check it's previously pressed, we can just get the value of axis states of axis name. This will help us understand if this axis was pressed in the previous frame, we also have to update its value to the new, to the currently pressed value. Okay? We don't need the line anymore. We are doing that from here. When we get the axis like this, we will get narrower because the first time this function is called, the axis state will not have that axis. Here. We can just check if the axis state contains that axis. If it doesn't contain, then we can just add it. I'll call axis states to add for the key L pass, the axis name and for the value L pass falls because we're adding it for the first time. All right, so now we have a generic function with which we can check if any of the axis on our joystick is down. Let me just make this class a singleton so that we can easily access it from any script that we want. So create a public static instant of the scal power and then from the awake function I'll initialize it. Okay, now from our combat controller we can just use joystick helper instance do get access down and for the access we can just pass lock on trigger. Now this slowly return if the lock on trigger was pressed in the current frame. Okay, let's go to Unity. First we have to attach the script to a game object. So create a game object over here called joystick helper. Let me reset its position and I'll add the joystick helper script to it. Now if we play the game, we should be able to lock onto an enemy by pressing the left trigger on the joystick. We should also be able to attack an enemy by pressing the X button on the joystick. Yeah, that is working fine. We have added controller input for the compact. I'll chop the video here. Thanks for watching, and I'll see you in the next video. 28. Stunned After Taking Hit: Here in this video, we'll be making some improvements to our combat system. So the first improvement that I want to make is I want the enemy to be stunned for some time after taking an attack from the player. Okay, so let me show you why we need that. Just to make it easier test, I'll just remove the second enemy. And if I go ahead and attack the enemy while he's moving, you can see that right after we attacked, the enemy just kept moving back like nothing had happened, right? The problem with this is we won't be able to perform combos and stuff if the enemy keeps moving after the first hit, right? We don't want that. Instead we want the enemy to be stunned for some time before going back to the normal states. Okay, to implement that, we'll have to make getting hit functionality a separate state, right? Right now getting hit and playing the hit reaction is handled from the male fighter, from this function, right? It can happen from any of these states. If that happens, we won't be able to control how the hit reaction affects the enemy. What we can do is when we play the hit reaction, we can change the state of the enemy to a separate state called getting hit or something. All right, first let me create a state for that in here inside the state's folder of the enemy. I'll go ahead and create a new script and I'll call this Getting Hit State. Okay, so this will be a state of the enemy controller. And from the state still, go ahead and our right, the enter function. From the enter function, I'll just cache a reference to the enemy just like we do from all our states. Okay, so we have to switch to the state when the enemy gets hit by the players attack. Right from here we can't just switch to the getting it state by calling enemy controller getting chain state. The reason is because male fighter is a script that is used for both the enemy and the player, right? We did that because we want to reuse the code as much as possible. From here we can't write any line of code that is specific to the enemy. Okay, if you do that, then it won't make sense when this function is executed for the player. From here we can reference the enemy controller. We have to figure out a way to notify the enemy controller that the enemy got hit without referencing it from the male fight descript. Okay, how can we do that? We can do that by using a delegate over here, we can create an action delegate. I'll explain what this is in a moment. First, let me write it. To use the action delegate, we have to import the system namespace. Yeah, over here we can create an action delegate. And I'll just call this on hit. Okay, so what is this action class that you see over here? So you can think of this as a special data type that can store functions in it, okay? In this variable we can store a list of functions. When we call this action, all the functions that are stored in it will also be called. Okay? When we define an action like this, we can reference it from the enemy controller and we can store functions in it. Okay, let me show you how we can do that. From here, we can access the on got hit action, we can attach a function to it. We can do that by using the plus equal to operator. Over here, I'll just to find a function called react to it. Then I can store that function to the on got hit action simply by using this plus equal to operator. Okay? Now, this function will be stored in the got hit action. Now, if we call this action, let's call it from the play hit reaction function. If I call the action like this, then what will happen is all the functions that are attached to this action will also be called, okay? So since this function is attached, this function will be called. Then the on got hit, action is called. Okay. So basically what we just did over here is we found a way to notify the enemy controller when the Malay fighter takes a hit without referencing the enemy controller in the Malay fighter. Okay, so actions are a way to inverse the dependency, right? Right now we don't have to make the male fighter depend upon the enemy controller, but we are doing the opposite. Right? You're making the enemy controller depend upon the male fighter, which is okay. But making the male fighter depend upon the enemy controller is not okay, because this is something that we re use for the player. All right, in such cases we can use the action delegate to inverse dependency. Okay, when we define an action like this, it is a good practice to make it an event. The reason is because events add an extra layer of security to the delegates. So let me explain what I mean. If this was not an event, then we would be able to completely replace all the functions in this action by using the equal to operator. If I do this, everything in this action will be replaced. Allowing that can lead to mistakes because we might accidentally replace it from some other place and the function that I attached over here will be gone. Okay? It's always good to use plus equal to attach the function to the existing list instead of completely replacing it. The thing is, if we make this an event, then we won't be able to replace this, will get an error in that case to the events. We can only add a function like this. We can't replace it entirely. Okay. So yeah, it's always a good practice to make our action delegates at event. Another thing is when we call the action like this, we might get an error if on got hit. Action doesn't contain any function, okay? So just to be safe, what we can do is we can use an unconditional operator and then call the invoke function, okay? So this is the same as calling the action directly, but let's make sure that we won't get narrower. If on got hit, action is not okay. Now, whenever an enemy gets hit with an attack, we will call this react to hit function. From this function, we can change the state to the getting hit state, right? Yeah, from here we can just call the chain state function and we can pass the getting hit state. All right? We haven't defined that state over here, so let me define it in the enum, and I'll also add it to our state dictionary. Okay, Now I should be able to change the state to getting hit. All right, this will work fine. But there's actually an easier way to write this. We don't have to define a new function and attach it like this. Instead we can just use a lambda function like this. Okay, lambda function is just an easier way to define function. Using this, we can define functions in a single line. We don't have to define it and add it separately. Okay, You can use the other method if you prefer that, but this is just a cool way to do it. Okay, Now whenever the enemy gets hit, we'll go to the getting hit state. And from the state once the hit reaction is complete, we want to make the enemy stunt for some time and then go back to the combat movement state. Okay, from the getting hit state, we need a way to know if the hit reaction is complete or not. If you want to, can use the inaction property of the male fighter from the execute function. But there is actually a more simple way of doing it. We could again use an event and listen to that event from the getting hit state. Let's actually do that over here. I'll just replicate this and create another event called on hit reaction. Well, I'll just call it horn hit complete to keep it short. Okay, from here, once the hit reaction animation is completed, I'll call horn hit complete and I'll invoke it. Okay. Now from the enter function of the getting it stated, we can just listen to the on hit complete event that's inside the male fighter of the enemy. I'll call enemy fight On hit complete. I'll just attach a lambda function to it. From the function, I'll call another corotine. Okay, I'll name the corotine. Go to combat movement and runs routine. Firstile weight for a small time just to give the impression that the enemy is stunned after the attack. While you seal return new weight for seconds function. Let me actually define a salalized field variable for the seconds to wait. I'll just call this something like stern time. I'll sell it something like 0.5 default. Okay. Now we can use that over here. After that we can go ahead and change the state to the combat movement. I'll call enemy chain state. I'll pass the combat movement, um, as the parameter. Okay. Now from here from the lambda function picking is called chart corotinell, the combat moment, corotine. All right? Yeah, this is all you have to do now. When the enemy gets hit, we'll go to the getting hit state. Once the hit reaction is complete, we'll wait for a small time and then go back to the combat put. Okay, so this will make the enemy stunned. Let's go it and test this. First we have to attach the getting hit straight to our enemy prefab. All go inside the prefab and attach it like this. Oops, I got the wrong script, so let me attach it again. All right, now let's start testing. Now if I attack the enemy while he's moving, you can see that the enemy stops retreating back and stays in the stunt state for some time. Okay, you can adjust the value of the stunt tim if you want the enemy to be stunned for a longer time. Another thing I want to change is in the enemy manager script when we select an enemy for attacking. I'll also add an additional condition over here to make sure that the enemy is in the combat movement state. Okay, I'll use in state function. I'll check if the enemy is in the combat movement. Adding this condition, we'll make sure that we won't select enemies that are in other states, like getting hit fight. That will look really weird if an enemy who is getting hit suddenly starts attacking us, okay? Next, After implementing the getting hit state, we'll have an edge case that happens when the enemy gets hit before actually seeing the player. Let me show you the issue first. So let me run the game. And if I hit the enemy before the enemy actually sees us, then you can see that we have this null reference exception that is happening from this line. And the reason why it's happening is because the enemy got hit before seeing us. After waiting for the stunt time, we'll switch to the combat moment state. Right, when we are in the combat moment state, the enemy hasn't seen us yet. And the target will be null when we are executing this line, which causes the null reference exception. Okay, so currently we are setting the target when we see an enemy from the idle state, right? But this time we did not switch to the combat moment from the idle state. Instead we switched from the getting hit state. Okay? So to keep things simple, what we can do is in the execute function, if enemy target the null, then we can go ahead and find the target and store it in this property. Okay, so we have already written the code for finding the target from the targets in range in the ideal state. So we can also reuse this code from here. Okay, what I'll do is I'll actually move this code into a separate function and use that function from all the places from where we need to find the target. I'll actually move it into the enemy controller Here I'll create a public function called find target. This function will return a male fighter. Okay? And to this function, I'll copy paste our forage loop for finding the target. Okay, since we are in the enemy control itself, we don't have to use enemy dot. We can access all these properties directly from here. We don't have to set the target and change the state to combat moment or anything. We just have to return the target if the target is in the enemy's field of view. Okay, so from here I'll just return the target. And if we don't have any target, then I'll just return null at the end of the function. Okay, so now from the idle state we can use the fine target function. I'll call enemy fine target. And I'll store the result in the enemy target property. Then if enemy target is not, then we can go ahead and change the state to combat movement like we do over here. Let me do that. This is all we have to do so we can get rid of the old. All right, next we can do the same from the combat open state for finding a target. If the target is not, let me call the enemy, do find target function and store the result in the target. This will find the target if the target is currently not set. Okay, one more thing I'll do from here is if enemy target is null even after calling the fine target function, that means there is some other issue and we don't have any targets nearby. Right, So in that case we can simply switch back to the idle state because we can't be in the combat popen state. If there isn't any target, I'll call enemy state. And I'll change the state to the idle state. All right, and I'd also just turn from this function because we don't want to execute any of the code below. All right, I'm just trying this for safety. In most cases, the target won't be null after calling the fine target function. All right, by the way, I made a mistake over here. This should be equal to equal to null. Instead of not equal to null. I will set the target if the target is null. Let me go to it and test to see if the issue is fixed. All right, so now we attack the enemy from behind. You can see that we don't have that issue anymore. Yeah, we have made an improve video. If you attack the enemy while he's moving, he'll just stand there and stay stunned for some time. We'll be able to perform combos on the enemy. I'll stop the video here and I'll see you in the next video. 29. Long Range Attacks: Ron. In this video we'll add long range attacks to our combat system. If the player is standing at a distance from the enemy, then the player will perform the long range attack, and otherwise the player will perform the normal attacks. Okay, so let's look at how to implement this. First we have to find an animation for a long range attack. I'll go to Miximo. This is the animation that I'll use. Okay? The player covers some distance in this attack. It's the E to be perfect for a long range attack search. And you'll find this animation. I have already downloaded it. Under the Animations folder. Inside combat, I add the spin slash animation. That's what I named the animation. Okay, first I have to rig this animation. So I'll make a Temanod and use the pad of the Eric Archer now should be able to preview the animation. All right, we don't want the last few frames of this animation. All right. Right now the rotation is not a look match. If we make this animation a bit shorter, somewhere around here, the loop match will become orange. I'll just change the end to something like 24. Okay, so I want to make this loop match because I don't want to use the root motion of animation for rotating the player. The initial rotation and the final rotation is almost same. So we could check baking interpose instead of using the root rotation. And then I'll change the based upon to original. Okay, then for the y root transform position, I'll change the based upon feet. I'll also use bak interpose. Okay, so let me go ahead and apply it next. Let's add this animation to our animator controller. So let me just drag and drop the sprint slash animation over here, and I'll make a transition back to the empty state for the name. Let me just remove the space between the spin slash because we haven't used spaces for any of our animations. Okay, next let's strike the code for performing this long range attack. I'll open up my male fighter script in here, I'll create a new list of attacks, and I'll call this long range attacks. Then from the attack function, we have to check the distance between the player and the target of the attack. All right, if the distance is above a certain threshold, then we have to perform the long range attack instead of performing the normal attacks. Okay, In this function. First, in reference to the target of the attack, so that we can find the distance between the player and the target of the attack. What I'll do is in the parameter of this function. Instead of taking the attack direction, I'll take the target of the attack. The target will be a male fighter. I'll also make it a default parameter because we should be able to try out the attacks even without a target. Okay, and since we have the target, we can find the attack direction from it, right? We can subtract the position of the target and the player to find the attack direction. Over here, I'll define the attack direction by default. I'll just send it to the forward vector of the player. But if the target is natcoonal, then we can find the attack direction by computing the vector to the target. We can get the vector to the target by subtracting the position of the player from the position of the target. All right, here I'll just set the component to zero, because we only want the direction in the horizontal plane. Then we can find the attack direction by normalizing the vector to target. Okay, here we have another. Because the attack direction is not an ullible vector, it's just a normal vector. We can remove the value property from here. Now when we call this function, we have to pass the target. Instead of the attack direction in the t to attack function. Also we have to change the parameter to target. Okay, I'll pass that while calling the attack routine. Now when we call the trite to attack function from here, we just have to pass the enemy to attack, the enemy to attack is the reference of enemy controller. I'll call fighter to get the male fighter. Okay, now we don't need these lines where we calculate the direction because we're already doing it from inside the attack function. Okay, this should work just like before. But now we also have a reference to the target. And now we can find the distance between the player and the target. And then decide what attack to perform based on that. Okay, since we have already calculated the vector to target, we can easily find the distance by taking its magnitude. Right? Distance will be vector to target magnitude. All right. Magnitude will be the distance of the vector. And when we normalize it, we will get the direction without the distance, okay? So next, if the distance to the target is greater than a certain threshold, then you have to perform a long range attack instead of performing the normal attacks. Okay? So what I'll do is over here I'll create another setlized field variable. And I'll just call this something like long range attack threshold, okay? And I'll set it to something like 1.5 by default, okay? And from here, if the distance is greater than the long range attack threshold, then we have to perform the long range attack, right? Right now we're referencing the attack directly from the attacks list by using the Bo count as the index, right? When this condition is true, we can't use this. Instead we have to use the long range attack, right? To achieve that, what I'll do is I'll create a variable called attack By default, I'll set it to this value. Attacks of bo count. Okay, I'll use that variable over here instead of referencing it directly from the array, From the list, not array. So let me change all the places where we are using attacks of combo cook. And I'll replace it with the attack variable. Okay, let me also change it over here. Over here. Okay. I hope I miss any place. We can just sell the strip it and do a search just to confirm it. Okay. Yeah. We have changed everything now. What we can do is if distance is greater than the long range attack threshold, then we can set the attack as long range attacks of zero, okay? So since you only have a single attack in this list, I'm just taking the first element to make this more interesting, what you can do is you can add more attacks to this list. And you can just take a random long range attack so that you'll have some variety in the combat. But I'm just going to take the first element because we have a single long range attack right now. Okay? All right, so this is all you have to do to perform the long range attack. So let's go to the T. And first we have to attach a long range attack to the meli, fight descript of the player. Right, so we have to create the attack scriptable object first. I'll just duplicate our slash attack, and I'll rename this to Spin. Okay, I'll also rename the animation name from here. We also need to find the impact, start time, and the end time. Let's check the animation to find that. Okay, so we can start the impact somewhere around here, around 54 percentage. We can end it somewhere around here, around 84, 85 percentage. Okay, let me go ahead and input those values into the impact Start, time and time. Start time will be 0.54 and the end time will be 0.84 All right, now let's attach this attack to our long range attack list. All right, now when we test the game, if you attack the enemy from a distance, you can see that the player is using a long range attack, but he's not attacking correctly. Right? Let me just run it again to show you if I attack from here. He's not moving in the right direction. Okay, That is because the player is using the root motion of the animation to move. But for long range attacks like this, we don't want to depend upon the root motion. Instead we want to make sure that the player is moving in the direction towards the enemy. Okay, so we'll have to move the player manually from the code, instead of depending upon the root motion of the player. What I'll do is for each attack, I add in optional property called move to Target. And if that is turned on, then we'll move the player towards the target of the attack while the attack is being performed. Okay, we need this because we can't depend upon the root motion for every attack. Yeah, let's go ahead and implement this. Open up the attack data script in here. Let me just duplicate this, and I'll create another property called Move to target. Okay, so this will be a bulling property that will indicate if we should move towards a target while attacking. Okay, for this to work, we also need some additional parameters. So we'll need a float called distance from target. Okay, so let me explain what this is. We don't want to move to the exact position of the target that look really weird. The player and the target will overlap at the same position if you do that. Instead of that, we need to stand at a distance from the target while attacking. Right? It'll be around 1 meter or 0.78 meters or something. Okay, So I'll just set it to one by default. Then we also need another float variable, and I'll call this one max move distance. This will be the maximum distance the player can move while performing the attack, okay? So this is just to make sure that the player won't be able to move really long distances. If the enemy is far away, that will make the attack look very unrealistic, right? The default value, I'll give something like three. Now when we are performing the attack, we have to move the player towards the target If the motor target bullying is true. Okay, What I'll do is over here first I'll create a vector three called start position. This will be the starting position of the player. All right, and then I'll create another vector three for the target position. This is the position that the player must reach. Initially, I'll just set it to zero and we'll find it from here. Okay, the target position will be the position of the target minus the distance from target offset, right? We don't want to reach the exact position of the target. We surely reach at this distance from the target, right? The target position will be the position of the target. Minus attack direction, multiplied by the distance, target offset. Okay? We can calculate the target position like this, by the way, by calculating the distance here. Also, we can subtract the distance from target. Because our player won't be moving this whole distance. The player will be standing at this distance, right? Yeah, we can calculate the target position like this, but one thing that we are missing here is we're not considering the maximum distance if he just uses. The problem is if the enemy is far away from the player, the player will move long distances, which will make it look unrealistic. We also have to check if the distance is less than the maximum distance, right, then we can calculate the target position like this. I'll just change this to less than or equal to. And otherwise, the target position should be calculated based on the maximum distance. All right, so the target position will be the starting position plus the maximum distance in the attack direction. Okay, let me do that. The target position to starting position plus attack direction multiplied by the maximum distance, okay? And by the way, we really need to do all this if motor target pulling is true, okay? As I'll check the value of motor target pulling and I really calculate the target position if motor target is true. All right, now we're calculating the target position Next, while performing the attack, we have to move the player towards the target position. Right from here I'll check if the target is not et attack Mott is true. If both these conditions are true, then we can move our player towards the Taggert position. For that we can just use a simple lope. Let me call vector three lob. I'll pass the starting position as the first parameter, the tag position as a second parameter. For the time, I'll just pass the normalized time. Okay, let me set this position back to the position of the player. This will move the player or let me just call this attacker because male fighter is common for both the player and the enemy. So this will move the attacker towards the target while performing the attack. Okay, so now we can go to humanity, and once the script reload is complete, we should have the new parameters over here. By the way, let me just add a header to segregate these over here in the attack data. I'll go ahead and add a header attribute. I'll just call this move to target. Okay, this is throwing an error because for colon syrilized field attribute, we also have to use field header attribute. Okay, that should fix zero. And now this looks much better for the sprint slash attack. We can turn on the motor target checkbox. And this should move the player towards the target while performing the attack. Let me try to distinguish. Yeah, you can see that performing the attack, the player is moving in the right direction. Okay. But I think the distance from target is a bit high. That's why the player is not reaching the target. Let me just reduce it to something like 0.5 and try it again. Now we can see that while performing the long range attack, the player is moving in the right direction and the player is also hitting the target. Okay, So the long in attacks are not perfect, right? Now If the enemy charges towards us while performing the attack, then we'll go through the enemy. Because we calculated the target position before the attack, right? We calculated this before the attack. But the enemy moved from this position while the attack was being performed. Okay, we'll fix that issue in the next video. So, yeah, I'll drop the video here. Thanks for watching and I'll see you in the next video. 30. Moving To Target Improvements: Here in the previous video we implemented long range attacks and we created a system for moving the attacker towards the target while performing the attack. Right, in this video we'll be making some improvements to the system and we'll also fix some issues that we currently have. Okay, right now we have a system to move the attacker towards the target. But one limitation of this is the movement to the target will always happen throughout the entire duration of the attack. Okay, That works fine for the spin slash attack, but it might not work for other attacks, okay? For example, we could also use this system to move our character a little while performing our normal slash attack, this one, right? But for this attack, we can't move the character throughout the entire duration of the attack. Because after this part, the character is pulling back the sword and going to the ideal position. Right? During this part we should not move the character. But yeah, in the first part of the attack, we could add a little bit of movement so that the player will reach the target and the chance of hitting the target is more okay. So to be able to implement that, what we need is we need to be able to specify a time range of the attack in which the movement should happen. Okay, if you specify that, then we can make sure that the character slowly move in that time range. Let's go ahead and implement that. Let me open up the attack data script here. I'll just duplicate this. And I'll create another property called start time. This will be zero by default, and then I'll duplicate that and I'll create move time. And this will be one by default. Okay? These properties will take normalized time. Zero means start of the attack, and one means end of the attack. Okay? By default the movement will happen throughout the entire attack animation. But if you want, we can change this right now in the maley fight descript, when we are moving the character towards the target, we can make sure that the movement only happens between the start and end time that we specified over here. Okay, in the L, we can't simply pass the normalized time, because if we do that, then the movement will happen throughout the entire attack animation. Instead of that, we have to find a percentage time from our normalized time based on the move, start and end time of the attack. Okay, we can easily find a percentage by using this formula that is normalized time minus start time divided by end time minus start time. Okay? So this will give us the percentage of the normalized time in between the start time and the end time. All right, I'll just call this percentage time and I'll pass it as the time parameter of the lobe. Okay, now we can test this for the slash attack. I'll turn on move to target. And here we have to reduce the maximum distance, because this is not a long range attack. I'll reduce it to something like one or something even smaller, like 0.8 Okay, distance from target will be 0.5 just like a spin attack. Then we have to specify the move, start time, and end time. The default values are not correct over here. I guess I saved it before actually setting the value. Not a problem. We can just select everything and change the default value to 0.1 Okay, but we don't want to move the character throughout the entire attack. Let's find out the start and end time by looking at the animation, the slash animation. We want the movement to happen only until this point. Somewhere around here, 46, 48. That's right after that the player is pulling back the sword, so we don't want to move forward during that part. Okay, so I'll go back to the attack scriptable object, and for the end time I'll give 0.46 for 46 percentage. Okay, so now we can try testing this and okay, looks like I made a mistake in the formula, so this should be attack start time. All right, so now let's start testing it again. Go close to the enemy and perform the attack. You can see that our character is moving forward while performing the attack. The chance of fitting the enemy is okay. Next I want to fix some issues that we currently have. To show you the issue, what I'll do is I'll just duplicate this enemy. And I'll create another enemy right next to it like this. Let me actually keep them a bit closer. Now if I go ahead and attack from here, you can see that both enemies are playing the hit animations. I don't really like that. With our normal attacks, we should only be able to attack a single enemy, right? It is just my preference. If you want, you can keep it as it is and let multiple enemies take hit from a single attack. But I don't really like this. Let me go ahead and prevent that from happening. To do that, what I'll do is I'll create a property called Current Target over here. Actually we just need a private paper because we'd only be accessing it from the male fight descript. I'll set the value of this from here. At the start, I'll set the current target to the target that was passed to the attack function. At the end, I'll set it back to null. Okay? So this variable will store the target that we are currently attacking. And by the way, since we're storing it, we also have to make sure that we're passing the target whenever we are calling the attack, we're also calling it from here to perform the combo right from here. Also we have to pass the target. Then we also have to pass it even when you're calling the try to attack function to perform the enemy's attack. Right now we're only doing it for the player, but we can also easily do that for the enemy. When calling tried to attack, we can just pass enemy target as the target of the attack. Okay, So now we are always passing the target and the target will be stored in the current target variable. Okay, so now when we detect a collision between a weapon and the character, what we can do is we can check if the current target of the attacker is this character who took the hit. Okay, so this is a attacker, so let me actually store it in variable because we'll have to reuse it. All right, from here we can just say attacker transform. Then we have to check if the current target of the attacker is same as the character that took the hit. Okay, if it's then we can just return. If it's not equal to this, then I'll return. And I won't play the hit reaction. Okay, we'll only play the hit reaction. The hit box hits the intended target. All right, now when we perform a hit, both of these characters should not play the hit reaction, right? Only one will play the hit reaction. That is much better. Next, there's another issue I want to show you. If I keep chasing this character while that character is in the retreating state, then that character will keep moving backwards like this. All right? We can fix that issue pretty easily in the retreat after state. Right now we are stopping that state and going back to combat movement only after the distance between the player and the enemy becomes greater than this threshold, right? So the problem with this is if we keep following the enemy, the enemy will always move backwards, right? So it fixes from here. Instead of checking the distance between the enemy and the current position of the player, we can check for the distance between the enemy and the position of the player at the start of the retreating state. Okay, over here I'll just create a vector three table called target position. And I'll store the initial position of the player. In this we can get that from enemy target transform position. We can pass that into our function for calculating distance, okay? Now that issue should be gone. Okay? Let me also hit the other enemy. Now if I chase the enemy, you can see that the enemy will stop after a certain distance. Yeah, that issue is fixed. So I'll stop the video here and I'll see you in the next video. 31. Combat Improvements & Edge Case Fixes: In this video, we'll make some improvements and fix edge cases in combat. Right now in the combat system, the player can just win the fight by spamming the attack button. We'll pin such things and we'll make it so that the player will have to fight strategically by using counterattacks and all that. Let's start the video first. Let me clean up the code a bit so that we can avoid issues and edge cases. So the first thing I want to do is over here, while we're passing the enemy to the try to attack function, I want to use a null conditional operator. All right, if we don't do this, then we'll get an exception when we try to make the player attack when there is no target enemy. Okay, we need to add this null conditional operator over here in the attack function of the male fighter over here. I want to add another condition and make sure that there is at least one long range attack. I'll check long range attacks do count is greater than zero, then I'll set the attack as the long range attack. Okay, If you don't do that, then we'll get an exception if no long range attacks we added to this list. Okay, So the next issue that I want to fix is in the getting hit state. If we enter the getting hit state again before this core routine is complete, then the problem is we'll go to the combat pit state from the first time the getting hit state was called. Okay, This issue is not noticeable because our stunt time is really small. But if your stunt time was like three, 4 seconds, then you'll really notice this issue. All right. It fixes. What we have to do is while entering the getting hit state, we have to stop any cotines that were previously running. Okay, so to do that we can just stop all cotines function. This will stop all the cotines cell running in the script. Okay, we have done some clean up. Next I want to make the player move towards the enemy at for the horizontal and the Spartachic attack also. Okay, right now we're only doing it for the slash attack and the spin slash attack. But we can also add a little bit of movement for these two attacks. First, let me do it for the horizontal attack. I'll turn on move to target. For the distance from target, I'll set something like 0.9 I'll reduce the max more distance to something like 0.8 I believe that was the value that we used for the slash attack. I'll use that same value over here. Then we need to find the move start time and the move end time. Let's look at the animation for that. This is the horizontal slash animation. We can start the movement from the starting of the animation. We can end it somewhere around here, Around 36 percentage. Okay, We don't want any movement after that, because the player is pulling back the sword. After that point, we want the movement to happen 0-36 percentage. Okay? In a horizontal attack, the move start time will be zero and the move and time will be 0.36 Okay. Next, let me also add movement to the kick attack. I'll turn on more to target, and again we'll change the distance to 0.9 I have already played with these values. I know that 0.9 is like a good value. You might be using different attack animations. You can play with these values and find the best value that suits your animation. Okay, next, tell, change the maximum distance to 0.8 then we have to find the start time and end time again. Let me look at the animation. Okay. We can start the bopen at the start of the animation. We can end it somewhere around here. Once the kick is complete, that is 44 percentage. Let me go back to the attack scriptable object here. The start time will be zero and the end time will be 0.44 All right. Oops, I just change it for the spin slash attack. I have changed for the Sparta kick attack instead. Okay, yeah. Both these attacks should have similar distance from target and maximum distance. Because they are like combo attacks that should be performed from the same distance. The maximum distance is the same, but distance from target is 0.5 We can actually make it 0.9 itself. It's good to have the distance from target of our combo attacks has the same value, right? Because those attacks will be performed from the same spot. Yeah, let's try testing this. Okay, let me bring him over here. Yeah, you can see that the player is moving towards the enemy while performing each attack. All right, so that is working fine. The next thing I want to improve is right now the enemy won't be able to hit the player while the player is attacking. Okay, The problem with this is the player can just spam attacks continuously and the enemies won't be able to hit the player. Okay, So let me just show it to you if I go over here and if I spam attacks on an enemy like this, then the other enemy won't be able to hit me. Okay? I can just spam attacks and I'll eventually win the fight. That should not be possible. We want the player to fight more strategically by using counterattacks and all that, instead of just spamming attacks at the enemy. Okay, the reason why this is happening is because right now, when a hit is registered, we really consider it if the character that got hit is not in any other action, okay? If the player was in an action like performing an attack, then that hit won't be considered. We can't use this because this will allow the player to spam attacks and not get hit. Instead of this, what I'll do is I'll create another weighty pull over here called is getting hit or is taking it. Okay. I'll set it to false, where default and then on the play hit reaction function while setting in action, I'll also set is taking it to true and at the end I'll set is taking it to false. Okay? Now from here, instead of if the player is not in action, we can check if the player is not taking hit. All right, so now the character won't take a hit while he is already taking a hit. But he'll take hit during other actions like performing attacks. By the way, I'll also add another condition here. I'll check if the player is not in counter, we don't want the player to take hits while performing counter attacks. Okay, by the way, since we have this is taking it fab, we can also check that while we're attacking from this ile loop, if it becomes true, then we can just break out of the while loop and stop that attack. Okay, so let's just this now. All right, let me go ahead and try spamming attacks on this enemy. Yeah, now we can see that while I'm attacking, I'm also getting hit, right? But another problem that I can see here is the player can attack immediately after taking a hit. Right? Unlike the enemy, we're not preventing the player from attack while the player is taking a hit. Okay, so we have to prevent that from here. From here we can add another condition and check if the player is not taking hit. Okay, the variable that we created over here is a private variable. We can just make it a public property so that we can access it outside this class. All right, let me add and a private setter. And I'd also make the first letter upper case so that we are following the naming convention. All right, from here I'll check if male fighter is taking hit is false and we truly be able to attack if we're not taking hit. Okay, so now it's St testing this. Okay, so now we can see that we are not immediately attacking after we got it right. But one more thing I would like to improve is I would like to change the target of the player once we get hit. Right, right. Now if I'm currently attacking this enemy and if the other enemy comes and attacks me, then after taking the hit, the player is turned back to the old enemy and attacking him, right. Once the player gets hit by an enemy, the player's target change to that enemy. Let's also change that from the combat controller. Whenever the player gets hit, we have to change the target enemy of the player right from here. How can we know when the player is hit? We can use the on got hit event. For that, we have been using this from the enemy controller to be notified when the enemy gets hit. We can do the same thing from the combat controller to know when the player gets hit. Okay, I'll actually do it from the start function. So let me find the start function. I usually like subscribing to the events from the start function. Instead of the age function, I usually only use a wake function for initializing the references. Okay, from the start function, I'll subscribe to the on hit event of the male fighter. All right, so this function will be triggered whenever the player gets hit. And when that happens we can check if the target enemy of the player and the attacker who hit the player is different. Okay, and if they are different, then we can change the target enemy to the attacker who hit the player. Right, from this function, we need to know the attacker who attacked the player in the on got hit event. We can actually add a parameter for the attacker. To add a parameter to the action, we just have to use its generic form and specify the type that we want to pass as the parameter like this, okay? And once we do that, we will have an error over here because this event requires a parameter. But we are not passing the parameter that's right from here when in working the event. We can also pass the attacker as a parameter. But the attacker that we get over here is the transform. The parameter that we defined over here is a male fighter. We can actually get the male fighter in this function also. Instead of passing attacker dot transform, we can just pass the attacker itself which is the male fighter. I'd also change it over here. Now we have to use attacker transform dot position. Okay, now our on hit event has a parameter for the attacker. Now when we're attaching a function to it, that function should also have a male fighter parameter. Okay, we're also attaching functions to it from the enemy controller. I'll just write and find all its reference here. Also attaching a function from the enemy controller here. Also we have to define a male parameter for the attacker. All right, now back in our combat controller, when the player gets hit, we can check if the attacker and the target enemy of the player are different. Right, if they're different, then we can change the target enemy. From here I'll check attacker is not equal to the target enemy. The target enemy is a reference of enemy controller what we want to male fighter. So I'll target enemy fighter. Okay, if they're different, I'll change the target enemy to the attacker who attacked the player. Okay, again, since the attacker is a male fighter, we'll have an Ab and we try to assign it to the enemy controller. From here we have to use Et component and get the enemy controller okay. By the way, we only have to do this if we are in the combat mode. So I also had a condition for that over here. Now when an enemy hits the player, we'll change the target enemy of the player to that enemy who hit the player. Okay, let's go to Unity and testing this. Okay, that did not work. As I expected, the player should have attacked the enemy who attacked her last. But that did not happen. I posted the video and found out the issue here in the combat controller. When we are choosing the enemy to attack, we are taking the input direction, right? The problem with the input action is that if we do not give any directional input, then the input direction will be zero. All right, when we pass zero over here, the enemy to attack will not be selected correctly, right? If we can just prevent that by adding a check over here. So if the input action is not equal to zero only then we should use the input action, right? Otherwise, we should just use the forward vector of the player for the direction to find the enemy, right? So we can actually put this in a separate function to make our cleaner. Let me copy this whole thing. In the Player Controller, I'll create a new public function called Get Intent direction. Okay, and here are the spaces here. We don't have to use Player controller I because they are already in the Player controller script. All right, so we just have to return this. Now from here we can just use the get intent direction function. And it'll give us the direction in which we should th up the enemy to attack. Okay, I'm just adding an extra condition to make sure that the direction won't be zero. All right, so now let's try distinguis. All right, so now we can see that when an enemy attacks, we are changing the target of the player to that enemy who just attacked. That looks much better than the player continuing to attack the enemy she was previously attacking. I'm happy with this. Yeah, we have done lots of improvements to the combat system in this video. I'll stop the video here and I'll see you in the next video. 32. Health, Taking Damages & Dying: Hayborn. In this video, we'll implement health, taking damages and dying for both the player and the enemy. First, let's start implementing a health system. I'll open up the male fight descript. And over here I'll add a property for the health. The good thing is if we add the health in the male fighter, it'll be added for both the player and the enemy. We won't have to add it separately for a player and the enemy. All right, so I'll add it over here. I'll create a float variable called health. I'll actually make this a property just so that we can access the health from other scripts in case if you want to check if the player is dead or not. Okay, I'll make it a property with the private setter and I'll set its default value to something like 25. Okay. We can change this later. Let me make this Cz field so that we can set the starting health from the inspector. Okay. Since it's the property, we have to specify it as field colonized field. All right, so this will be the health of the character. We have to reduce the health whenever the character takes a hit. Right? Whenever the character takes a hit, we also have to reduce the health. I'll actually create a separate function for reducing the health, and I'll call this damage. This will take a float variable for the damage from this function. We just have to reduce the damage from the health. Okay? And we can also clamp it to make sure that the health doesn't go below zero. It's not necessary, but I don't like my health br reaching negative values. So I'll just make sure to clamp it at zero. All right, now whenever we take a hit, we can also reduce the health by calling the take damage function for the damage. I'll just give something like five for now later we can make it so that the damage will change based on the attacker and the attack that he's performing. Okay, but for now I'll just a five. All right, this will reduce the health of the character when he takes an attack. Next, if the health becomes zero, then that character should die, right? The way I want this to work is surely play the hit reaction if the health is greater than zero after taking the damage. Okay, if the health is greater than zero, then we have to play the hit reaction. Otherwise we have to play a death animation. All right, I'll create a separate function for that. Over here. I'll just call this play Death. I'll take the attacker as a parameter just in case you want to play different animation based on the attacker. For now I'll just keep it simper and play a single death animation every time. We can just call that function from here if the health is not greater than zero. Okay, so now from this function we have to play the death animation for that first we have to find a death animation and add it to our animated controller. Right? So I'll just go to Maximo and I'll find a death animation. So this is the animation I want to use. You can search for die and you'll find it. All right, so yeah, go ahead and download this animation. I have already done that. I'll go back to Unity and I'll import this animation to our combat folder. Okay, so this is the new death animation. So first let me it. All right, let me choose the Erica Archer and rig this animation. Now I should be able to preview it. Okay, so in the animation settings, I'll just change the based upon defeat. And I'll just keep everything else as it is now. Let me add this into our animator controller and I'll just call this something like far back death. Okay. Since it's a death animation, we don't have to create a transition back to the empty state because the player will be dead after playing this animation. Right from the play death animation function, we can just call animator cross fade and we can play the back death animation. Okay, so now when a character takes a hit, he'll play the hit reaction or the death animation based on the value of the health. Okay, if the character died, then we'll also have to do a few other things. For example, if the character is a enemy character, then we have to go to the dead state, right? If you don't do that, then the enemy character will still try to attack the player after he's dead, right? We don't want that. We have to go to the dead state, just like we do when the enemy dies from a counterattack. Okay, here we don't know if this character is a player character or the enemy character. The male fight descript is common for both. Right, so we can't just change the state from here. We were able to do it for the counterattack because counterattacks could only be performed on enemies. We knew that this character would always be an enemy, right? But taking damage is common for both the player and the enemy. From here, we won't know if this character is player or the enemy. We can't change the state of the enemy to the dead state from here. Instead what we can do is from the enemy controller, we are already listening to the on got hit event of the male fighter, right? We can handle that from here if the health of the character is zero. Okay, so the got hit event is invoked from the play hit reaction function. We can just move it outside the play hit reaction function and put it somewhere over here so that it will always be called when we get a hit. We also want this event to be invoked when the health becomes zero. And when the player dies, right, I'll just move it outside. And now from the enemy controller we can just add brass to this function. From here we can also check if the character died. All right, so I'll check if the, if the fighter health is greater than zero, then we can just go to the getting hit state just like we're doing right now. Okay. Otherwise we have to go to the dead state. Okay, I'll just call the chain state function and I'll pass the dead state. All right, so when we do this, there will be an edge case that we'll have to solve the edge cases from the getting hit state. We'll actually wait for some time before going back to the combat movement right here, I'll just have to add a single check and make sure that once the enemy is in the dead state, we should never go back to the combat movement state. Okay, so we should really go to the combat movement if the enemy is not in the red state. If you don't do this, then we'll have an edge case, where the enemy will go to the combat movement even after he is dead. Okay, so we can just add this check to prevent that. Yeah, this is all we have to do. So score Unity and test this. By default, the enemies and the player will have a health of 25. You can adjust and use a value that you like. The player's health is zero for some reason. I'll just make it 25. Okay, I'm just giving a low value here because it'll be easy for me to test. I won't have to perform like lots of attacks to kill the enemy. Yeah, now let's start testing this. So if I go attack one of the enemies after like five attack, you can see that the enemy is dead. Okay, the same will be the case for us. After getting fewer attacks, we will also die. So let me show you that, yeah, if we take few attacks from the enemy, our health will become zero and we'll also die. Okay, Yeah, you can see that it is working, but we have a few issues here. Even after we're dead, the enemies are still attacking us. We don't have to worry about this much, because once the player is dead, we'll go to the game of our state. We'll go to some menu where we can restart the game. But still, we don't want the enemy to attack right after we're dead. We want our enemies to be smarter than that. Another issue right now we can move the player violated. We should also prevent that to stop the player from moving. Once she's dead. What we can do is here in the player controller, while you're checking for the inaction, we can also check if the health of the male fighter is less than equal to zero. If that's the case, then we'll just return from here and we won't execute the code for moving the player and all that. Okay, if you add this, then the player won't be able to move after he's dead. Next, we should stop the enemies from attacking the player once the player is dead. Right, That what we can do is from the update function of the enemy controller, we can check if the target of the enemy is dead. From here, I'll check if target health is less than O eicozero, which means the target is dead. If the target is dead, we can remove it from the targets in range list. Okay? And then we can also remove this enemy from the enemy's in range list of the enemy manager. So that the enemy manager will not choose this enemy for attack. Okay? And then we have to change the state of this enemy to idle state, okay? But I don't want to do it from here itself. The reason is because it'll look weird if the enemy just suddenly goes to the idle state when the player is dead. Instead, I want some time to pass and the enemy to retreat back before going back to the idle state, okay? So I want to go to the idle state from here. Instead, I'll do it from the combat movement state. From here, I'll check if enemy target health psamiclzero. If that's the case, then I'll change the state to the idle state. Okay? I'll also reset the target to null. And I'll just return from here so that we won't execute any of the code below. Okay, so changing the state to idle from here will be much better. Otherwise it'll look weird if the enemy just changes to idle right after performing an attack. Okay, so let's try testing this just to make things easier. At rest, I'll change the health of the player to something smaller, like ten. So that the player will die in one or two hits. Okay, so let me test this. All right, so the players did and the enemy should go back and go to the idle state, okay. Now we can also move the player, since we're preventing that from the player controller. Okay, from here you can do other things like go to the game off screen and all that. That is up to you. We're not building an entire game in this series. We're building the combat system. You can build upon this and do the rest. We implemented health, taking damage and dying in this video. I'll have the video here. Thanks a lot for watching. And I'll see you in the next video. 33. Alerting nearby enemies when a target is spotted: Hey everyone. In this video we look at how to make our enemies at other enemies that are close to them when they spot a target. All right, right now the issue is I can just go ahead and attack this enemy, and the other enemy won't be alerted about this attack. Okay, that seems like a really dumb behavior for the enemy. Instead of this, when an enemy detects the player, that enemy should also alert all the nearby enemies. All right, let's implement that. Whenever an enemy detects a target, that enemy should also alert the nearby enemies. And set the same target for the nearby enemies. Okay, let's create a function for that inside the enemy control. Over here I'll create a public function called alert nearby enemies. Okay? And in this function, first we need to get all the enemies that are close to the current enemy, right? So we can detect the nearby enemies by using a overlap box, right? So what this will do is this will turn all the O that overlaps with a box that we create, okay? We can specify the dimensions of the box, and this function will turn all the objects inside that box. Okay? So here we are to specify the position and the dimensions of the box. The position, I'll just pass the position of the enemy for the dimension. Let me just pass a vector with ten in the x and z axis and one in the y axis. Okay? So the height of the box will be 2 meters total, because this is half extents, right? You can see that the second parameter is the half extends, which means the height will be the double of this. The height will be 2 meters and its length and width will be 20 meters, right? So we can actually make this a variable so that we can change it from the inspector. So here I'll create a property called alert nearby enemies range. Okay, let me set it to 20 by default and I'll also make it a citrilized field. All right. Now, begin this past that as the dimension of our, our lap box. The next parameter we have to pass rotation of the overlap box that we want to create. We don't want to have any rotation so I'll just pass cotton identity. For the final parameter, we have to pass the layer in which we should look for collisions. This is an optional parameter but it's good to pass the layer because we know that all our enemies will be in the enemy layer, right? So there's no need to check for other game chicks, we just have to check for the enemies. So we can do that by passing the enemy layer, so we don't have a reference to the enemy layer from here. I guess we can add reference to it from somewhere like the enemy manager here, I'll create a zerlized field property for the enemy layer. Okay, and we can pass that as the fourth parameter. Okay, so let me go to the enemy manager script and assign the enemy layer before I forget. Okay, so now back in our code, this function filter, turn all the enemies in this range. Basically, it'll get all the nearby enemies. And by the way, let me just make this name a bit more shorter, like alert range so that the code is not that long. That's just my personal preference. All right, so this function will return a list of colliders that overlaps with this box. So let me just show that in available, called colliders. And then we can use a for each loop to loop through all the colliders, okay? And if the returned collider is actually an enemy, then we have to alert that enemy by setting its target as the target of this enemy, right? First thing we can do is this function will also return the current enemy on which we're running the school, right? We don't want to alert the current enemy because it already spotted the player. We can skip the current enemy. If the game object of the collider is equal to the current game object, then we can just skip that enemy. I'll do that by calling the continued function. Okay, Then from the collider, I'll get the enemy controller component right. So the colliders can be of any game object, but we only warn the game objects that are enemies, right? By getting the enemy controller component, we can confirm that the collider is an enemy. So let me stow this in available, called nearby enemy. And then if nearby enemy is, if the nearby enemy does not already have a target, then we can go ahead and alert that enemy and set its target. Okay, so also check if that enemy doesn't have any target right now, we have to check if the target is equal to, equal to n. If that's the case, then we can alert that enemy by setting its target. Set its target to the target of the current enemy, okay? And then after setting its target, we also have to change its state to combat movement state, right? Once an enemy has a target, we have to go to the combat movement state. This function will alert all the nearby enemies. Now we have to call this function whenever an enemy spots a target, right one places from the idle state. If the target is not null, that means the enemy actually spot the player right from here. Along with changing the state to combat movement, we can also call enemy alert nearby enemies. And alert all the enemies that are close to this enemy. Okay, so when we spot the player and when we set the target, we also have to call the function for alerting the nearby enemies. Okay, another place from which we are detecting the target and setting it is from the combat moment state. The reason why we have this code over here is because there's a chance that we might reach the combat movement state before the enemy even saw the player right cases. If the player hits the enemy from behind, the enemy will go to the ten kit state. And then the enemy will go to the combat movement when the enemy reaches the combat moment state. If the target is not, then we are finding the target by calling the find target and setting it right. Since we're setting the target from here, we also have to call the alert nearby enemies function from here. But I think there's a better way of setting the target now since we have the on got hit event in the male fighter and since we are getting the attacker from here, we can actually set the target from here itself. We don't have to wait to reach the combat permit state. And we don't have to find the target again. The target is already passed as an attacker in the on got hit event. Right? Instead of doing it from here, we can do it from the on got hit event. So I'll actually remove this code. Okay, from here. If the health is greater than zero, that means the enemy took a hit and is not dead. In that case, we can also set the target and alert the nearby enemies. I only want to set the target if the target is currently null. All right, if the target is not, we can set the target after the attacker. This is much more efficient. We don't have to call the fine target function from here and loop through all the possible targets and all that, right? Then after setting the target, we also have to call the alert nearby enemies. Okay, yeah, this is all you have to do to alert the neighbor enemies. So let me go to Unity. And first I'll increase the health of the player. 200. We can test for some time without the player being dead. Yeah, now let me try testing this. All right, so now if I attack one enemy, the other enemy will also be alerted. Okay, we can also try placing the other enemy a bit away from the current enemy. If it's within the ten metre distance, then the other enemy will be alerted. So let me place it somewhere over here, within a ten meter distance. Now if I try attacking this enemy, you can see that the other enemy is also alerted. Okay, so we can also try placing the other enemy at some other location like this. And if it's within ten meter, then that enemy should be alerted. So yeah, you can see that it is working fine. Okay, we can even try adding more enemies in the scene. And when we attack one of the enemies, all the other enemies should be alerted. Okay, yeah, that is working fine. When we attack one enemy, all the other enemies in the scene are being alerted. I'll drop the video here. Thanks for watching and L see you in the next video.