Create a Third Person Controller in Unity from scratch

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hey everyone in this tutorial we'll create a third person controller and unity that looks like this so we won't be using any assets to build it we'll build it completely from scratch because it's a good way to learn the fundamentals of 3d game programming and it will give you the knowledge to customize the controller for your own games so while building the controller you will learn lots of important concepts like how to use unity's character controller component how to implement camera related movement how to use humanoid retargeting for reusing animations on multiple characters how to use physics for ground detection etc so there are lots of things that you learn while building this and by the way this is actually the first module of our udemy course gmt third-person parkour system in the course we'll build on top of this controller and create a more advanced controller that can use barco to traverse dynamic environments like this so i'll put a link in the description if you want to check out the whole course so with that let's start the video so first we'll start by creating the unity project so i have my unity hub opened over here so i'll click on the new button to create a new project so let me just name this something like barcode system course all right and i'll change the template to universal render pipeline just in case you want to use the shader graph of the vfx graph in the future all right so let me go ahead and hit the create button and it should create the project for us so this will take some time so i'll pass the video and get back to you once it's over all right so the project has been created so the urp projects comes with some example assets so we don't need them we are going to build everything from scratch so let me go ahead and delete the example assets and i'll also delete the folder containing the example assets okay and then we can also delete the tutorial info and the readme file we don't need them so next let's create a new scene so inside the scenes folder we already have a scene over here but i want to create a new one so i'll go to create and select scene to create a new scene so let me just name this something like test scene and i'll double click to open it so here i add a new plane game object so on the 3d object i'll select plane so this will act as the ground of our scene all right so let me just reset its position so that it's at the center and i also want to make this plane a little bigger so i'll change the x and z scale to something like five all right we have a much bigger plane so next i want to change the material of the plane if we use a plane material like this then it will be hard to understand if our character is moving or not so let me create a new material for this so under the materials folder i'll right click and create a new material so i'll call this material checkers all right and under the surface input we can change the texture of the material so if you click on the base map you can select the texture that you want to use so i'll just use this default checkers texture that comes with unity all right so now we can drag and drop this material to the plane to apply it so it's applied now but the checkers are a bit big so i'll increase the dialing to 10 to make the jiggles smaller so that looks good so now we have set up the scene to work with so next we can start building our third person character controller so we'll start by building the camera of our third person controller so 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 and i'll double click on it to focus and let me just place it above ground all right so now we want our camera to look at this player and rotate around it right so let's go ahead and write the script to achieve that all right so in the scripts folder we already have a script called simple camera controller but we are not going to use that we are going to build our camera controller from scratch all right so let me go ahead and delete it and then i'll create a new script called camera controller all right so let me get rid of all the default code in the script and in the script what you want to do is first we want to place the camera behind the player at a distance like this all right so this is the player and this is the camera so we want to place it behind the player at a distance so in the camera controller script first we need a reference to the object that we want to follow right so here i'll create a serialized field variable of type transform and i'll call this follow target alright and next we want to place the camera at distance behind our follow target right so 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 so i'll subtract follow target position by a new vector and this vector will be 0 in both x and y and in the z we should provide the distance so for now let's say we want the camera to be five units behind the player so i'll just put five for the z all right so let's go to unity and see the result of this so first we need to attach the camera controller script to our main camera all right so let me just drag and drop it over here and then we need to assign the follow target object so let me just assign the player as the follow target so now let's go ahead and run the game alright so you can see that the camera is placed behind the player at a distance so we can actually minimize the game view and take a look at it from the scene view so you can see that the camera is behind the player and its set position is minus five since the players that position is zero so it's placed five units behind the player right just like we specified from the script so 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 so let me create a new variable for that all right i'll make it a serialized field so that it's exposed in the inspector and this will be a float variable and i'll just call it distance and set its value to 5 by default okay so now in here instead of hard coding file i'll use my distance variable okay so now if you go to we can change the distance value from the inspector right so let me just put it back to five all right so now we are placing the camera behind the player at a distance so next we should rotate the camera around the player when we move the mouse right so we should rotate the camera both horizontally and vertically but first let's handle the horizontal rotation so how can you rotate the camera around the player like this so for that all you have to do is just rotate this vector right so this is that vector and if we rotate this vector by multiplying it with the rotation then it will be rotated like this based on the angle so let's go ahead and try this out in unity so to rotate a vector we just have to multiply it with a rotation so let's say we want to rotate this vector by 45 degrees so for that first we need to create a rotation of 45 degree so i can do that by using quaternion dot euler all right and in which axis should be rotated so the rotation here is horizontal right and if you want to rotate something horizontally then we should rotate it in the y axis right so in the quaternion.euler i'll put 0 for the x 45 for the y and 0 for the z so this will create a rotation of 45 degree in the y axis so if you're not familiar with quaternions and rotations i've already covered that in the introduction section of this course so be sure to watch that first all right so this will create a rotation of 45 degree and then to rotate this vector all you have to do is just multiply this quaternion to this vector all right and this will rotate this vector by 45 degrees so let's go to ut and see the result of this all right i'm going to play the game so 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 alright 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 so that's working as expected so next we want to rotate the camera around the player like this when we move the mouse horizontally right so that is pretty simple to achieve what we can do is we can create a float variable over here called rotation file and then in the update function we can add the mouse x input into the rotation by variable all right so i'll say rotation by plus or equal to input dot get axis mouse x all right so we'll be adding the joystick in the future but during the implementation let's keep this simple and use the mouse so now in the cortonian dot euler we can use rotation by instead of just hard coding 45 all right so let's go to your d and see the results 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 you can get a better view of it from the scene window okay so yeah you can see that the camera is rotating around the player in a circle okay so that's working fine so next we should make the camera look at the target when we rotate around it right so that's pretty easy to achieve all we have to do is set this rotation as the rotation of the camera all right so first let me store this rotation into another variable so that we can reuse it so i'll call this variable target rotation all right and here i'll multiply the vector with the target rotation and then we can also set this as the rotation of the camera so i'll set the transform dot rotation to the target rotation okay so now the camera should also look at the player so let's go ahead and test it all right so now you can see that as we rotate around the player the camera is constantly looking at the player so that's working so now we are done with the horizontal rotation of the camera so next we should also rotate the camera vertically like this right so 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 so here i'll create another variable called rotation x and then we should rotate the camera vertically when we move the mouse up and down right so to the rotation x i'll add the mouse y input all right let me just copy this line and change it to mouse y so this might be a bit confusing to some of you because we are adding mouse y to rotation x and mouse x rotation y right but the reason for this is because for horizontal rotation we should rotate around the y axis and for vertical we should rotate around the x axis right so 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 so let's continue with the vertical rotation so here i need to add the rotation x to the x of the cotronian.euler and now we should also be able to rotate the camera vertically all right let's go ahead and test it so 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 so we should set a limit to how much we can rotate vertically all right so we can easily limit that by clamping the rotation x value so to clamp a variable we can use math f dot clamp and what this function will do is it will take a min and max limit and if the value goes beyond the limit then it will just clamp the value to the limit so in this case rotation x is the value that we want to clamp and then we should define the min and max limit so i'll create variables for the min and max limit and i'll make them serialize field so that we can tweak it from the inspector okay so i'll call the first variable min vertical angle and let me set it to something like -45 by default all right and then i'll duplicate this line and by the way you can duplicate a line in visual studio by using the ctrl d shortcut all right so i'll duplicate the min vertical angle variable and create another one called max vertical angle so i'll set this one to plus 45 degrees all right so now we can clamp the rotation x between the main vertical angle and the max vertical angle okay so let's go here d and test this and 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 so now i can't move the camera above this limit i'm clamped over here and if i go down okay this minimum angle is a bit too much but i'm clamped over here i can't go beyond this point right so the clamping is working properly so 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'll look really weird so the camera should actually look at the chest of the head part of the player so we can easily achieve that by adding an offset to our target position so here i'll create a new vector2 variable and i'll call this framing offset okay and then instead of using the follow dot position directly i'll add the framing offset to the photo target position all right and let me store this in a variable called focus position so this is the position to which the camera should focus okay we can't simply add these two like this because because follow target.position is vector 3 and the framing offset is a vector 2 right so we can't directly add them so here i'll have to create a new vector 3 and then i'll have to pass framing offset dot x and framing of the dot by okay so that's all the error and now we have focus point so here instead of using the follow target dot position i'll use the focus position so let's go to unity and test this all right so right now it's still looking at the bottom because we didn't set the offset in the inspector so let's try changing the framing offset from here so here you can see as i increase the y offset our focus position gets higher and higher right so let me just set it to a value like one for now we let this is further when we bring in an actual character all right so that looks much better so next 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 so let me try setting it to something like -20 and by the way here you can see that the framing offset has been reset to zero this is because we changed its value then we were in the play mode and whatever changes that we make in the play mode will always be reset when we exit the play mode all right so let me set it back to one and now let's go ahead and test if the vertical angle is fine so yeah that's okay so now we are done with the vertical and horizontal movement of the camera all right so there is one more thing i want to add before i stop the video so i want to be able to control the speed at which the camera moves so that is pretty easy to achieve when we are updating the rotation x and rotation by variables from here we can multiply the mouse input with the speed value all right so here i'll create a new float variable called rotation speed and let me just set it to 2 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 so it's true right now but if you want you can increase it to a higher value so next i want to hide the mouse when we are playing the game so right now you can see the mouse when the game is being played so i want to hide that so to hide the mouse we have a property called cursor.visible so i'll set that property from the start function so let me create the start function over here and in the start function i'll set the cursor dot visible property to false so this will make the cursor invisible and then we can also lock the cursor by setting cursor dot lock state to cursor lock mode dot block all right so now we won't see the cursor when we play the game all right so you can see that the cursor is not visible anymore and 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 mode alright so just keep that in mind so now we have a decent third person camera but there's one more thing i want to add so some people prefer the camera direction to be inverted right so let's add a setting for that in our camera controller script so here i'll add two new boolean variables so the first one will be called invert x and the second one will be called invert y so if the invertex is true then we should invert the x rotation so we can easily do that by multiplying the mouse input with -1 right so what i'll do is i'll create two more variables for the invert value so first one will be called invert x val and the second one will be invert by val okay and we'll set its value from the update function so if the invert x is true then the value will be -1 and otherwise the value will be 1 all right so let me store this into invert x val variable and then i'll also do the same for the invert y val all right so now we can multiply the invert x val with the mouse x input and we can also multiply invert by val with the mouse y input okay so this should allow us to invert the camera moment so from the inspector i'll turn on invert x and invert y all right so now when we test the camera moment should be inverted all right so now we have a basic third person camera setup so next we'll import a model for our player instead of using a capsule and we look at how to make a character move like this so the character moment will be related to the camera just like we see in our third person games all right so 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 are using a capsule all right so let me switch this with an actual character so i'll be downloading the character from a website called mximo.com so this site has lots of good characters and high quality animations and they are completely free so i'll open up miximo.com and you'll have to create an adobe account to use this all right so i'll go to the characters section and download a character so the character i want to use is erika all right this is the character i want to use so i click on it and then click use this character so once you do that you'll be able to see the character in this window and 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 so let me click on the download button and for the format we have to select fbx for unity and then we want the pose in the post itself so just make sure these two options are correct and then you can click on the download button and the character will be downloaded as an fpx file all right so i've saved it to my desktop so now let's go ahead and import the character into unity so under assets i'll create a new folder called models so this is where we put all the 3d models so next i'll drag the fbx 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 so yeah you can see the character model but it doesn't have any textures on it so to fix that select the model and in the materials tab click on the extract textures button all right so we need to specify a folder in which the textures will be extracted so here i'll create a new folder for that let me call it textures all right and i'll select this folder okay so now we're getting this warning saying that normal map textures should be marked as normal map so here we just have to click on the fix now button and it'll automatically fix it for us alright so now we have the textures awesome so next let's implement the script to move this character so inside the scripts folder i'll create a new script called player controller alright so let me open it up in visual studio and i'll also get rid of the default code so in this script we should move the player based on the input of the user right so first i'll get the input from the update function so let me create the update function over here and then i'll get both horizontal and vertical input all right let me store the horizontal input in a variable called h and 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 so next let me create a vector based on these two inputs so i'll call this vector move input all right so this will be a vector 3 and 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 so this is a direction in which we should move the player and here we have to one more thing we have to normalize this vector so i'll use a normalized property to normalize this vector so what this will do is this will set the length of the vector to 1 if we don't do this then the diagonal moment will be faster than the moment in a single direction so that can be solved very easily by normalizing the vector okay so now we have the movement input so next we should move the character based on this input so remove the character i'll update the transform.position and to the position we can add more input so that the character will move in the direction of the input and then we should be able to control the speed of the movement right so for that i'll create a variable called move speed and let me just set it to 5 by default and here we should multiply the move speed with the movement input all right so now the character will move in the speed and finally we should also multiply this whole thing with time dot delta time so that the moment is frame rate independent okay so now the character should move based on our input so let's go to unity and test it all right so first we should assign the player controller script to our player so 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 and 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 alright so now we can go ahead and attach the player controller script to the player and then in the camera controller script the photo target reference will be missing because we deleted the capsule so now let's go ahead and assign our player all right so now let's go ahead and run the game so the camera is moving around the player just like before and now when we press the wasd keys or the arrow keys the character should move all right so the character is moving so if i press the up 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 so the movement is working as we expected but this is not how the character should move in a third person setup right 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 right 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 relate to the camera so first we need to get a reference to the camera from the script so let me actually create a variable for the camera controller over here all right and then i'll cache a reference to it from the awake function so since the camera and player are attached to different objects we can't simply use the get component function instead we have to get the reference to the camera's game object first so we can get the reference to the camera's game object by calling camera dot main property and then on that we can call get component and get the camera controller okay so let me cast this to the camera controller variable and now we can multiply the move input with the rotation of the camera all right so i'll get the rotation from camera controller.transform.rotation and then i'll multiply it with the mo input okay so i'll store this in a variable called mo direction i'll just say dir for shot and then here i'll use the movement direction variable instead of the movement input so this should rotate the movement input in the camera's direction but there's 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 so 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 so if we use the vertical rotation then the player will also be able to move up and down so we don't want that unless you're making a player that can fly so let me go to unity and show you what happens when we use the complete rotation all right so here the movement is related to the camera but the player can also move up and down so if the camera is facing up like this then the player will be able to fly all right so we don't want that so here we should only take the horizontal rotation of the camera so we can get the horizontal rotation from rotation y right so what i'll do is in the camera controller script i'll create a new property called planar rotation so this will be the rotation in the exit plane or the horizontal plane all right and in this property you should return a quaternion so i'll create a quaternion by using cortonian dot euler and here we should only consider the y rotation we should not consider the x rotation like we do over here so i'll pass 0 for the x rotation and then i'll pass rotation y variable for the y and then i'll pass 0 for the z so this will give us the planar rotation of the camera and now from the player controller we can simply multiply the move input with the planar rotation all right and by the way if you're not familiar with properties in c sharp i'll explain it real quick so properties are pretty cool feature in c sharp so usually in most programming languages if you want to return something like this from a class you would create a public function right so usually you would create a public function like get plain out rotation and 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 so properties are just like a function the only difference is they won't have this parenthesis that a function has right so you don't have this feature in most of the programming languages so i just want to give you a quick explanation in case you don't know what properties were and by the way if you want to use a function over here like this it's totally fine i just like using properties since they are shorter alright so let me get rid of the function so now the movement is only multiplied with the planar rotation so the character shouldn't be able to move up and down all right so let's go to unity and test it all right so the character is not able to move up and down but it is moving related to the camera so 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 so that's working fine so next when moving the character the character should rotate and face the direction in which it is moving right so we just have to set the rotation of the character to make it face in the right direction so from here i'll also set the rotation of the character so we want the character to face in this move direction right but more direction is a vector and for the rotation we have to pass a quaternion so we can actually get the rotation from a direction vector by using quaternion dot clock rotation function and we have to pass the directional vector in the parameter of this function okay so this will make the character face in the direction in which it's moving but we should really update the direction when the character is moving right so how can we check if the character is moving so for that i'll create a new variable called move amount over here so this variable will be a sum of horizontal and vertical input and if the more 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 sign of the horizontal and vertical input right here we don't care about the direction of the input we only care about the amount so if the horizontal input is -1 we should remove the sign and make it one so to remove the sign from a value we can use the math f dot abs function so here abs stands for absolute since this function returns the absolute value by removing the sign 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 so we can move the code to set the rotation inside this if and we can actually move this line also because there is no point in trying to move the character if the input is zero right so i'll actually move these two lines inside this condition all right so now the character should face in the direction in which it's moving okay so let's go to 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 right so let's look at how we can achieve that so to make the rotation smooth we should not set the rotation directly like this instead i'll store this rotation in a variable called target rotation all right so here instead of setting the rotation directly i'll store it to the target rotation variable and then outside this condition we can slowly change the current rotation of the player to the target rotation right so slowly change one rotation to another we have a function called quaternion dot rotate towards all right so in the first parameter we have to pass the from rotation so here the from rotation will be the current rotation of the player and then two rotation will be the target rotation and finally in the third parameter we should pass the amount by which we should change the rotation so using the third parameter you can control how slow or fast the rotation change should happen so i'll actually create a variable for that called rotation speed all right and 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 so here 500 is the angle of rotation all right so now we can pass it as third parameter then we should also multiply it with time dot delta time to make it frame rate independent and finally we should set the value returned by this function to our transform dot rotation all right so this will smoothly rotate the player instead of rotating it instantly and by the way let me split this into two lines because i don't like lines that are really long okay so now let's go ahead and test if the rotation is working so i'll just select the player and make sure that the rotation speed is 500 all right so now let's go ahead and test it okay so 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 so we successfully made our character move based on the input so next we'll set up the animations that we need we'll look at a concept called humanoid retargeting in unity which will allow us to reuse the same animation on multiple models so first let's download the animations that we need so i'll be downloading all the animations from miximo the same place from which we downloaded our character so here you also have animations so if you click on this animations tab you can browse all the animations available in miximo alright and by the way before you start selecting and downloading the animations make sure to select the character that you downloaded in the previous video so in my case the character is erika alright so i'll select the character and click on use this character alright so make sure to do this before you start downloading the animations this is important because when you download the animations miximo will automatically make it compatible with the character that you selected all right so now let's look at the animations that we need so first we need an idle animation so here i'm going to search for idle so you have lots of variations i'll just go with a simple title like this one all right and by the way you have few settings over here you can play with it if you want to modify the animations so here for this animation the hand of the character is really close to the body so if you want to have more space between the hand and the body then we can increase the character arm space so let me increase it to something like 68 all right that looks better so i'll go ahead and download this animation so while downloading you have a few settings over here so for the format make sure to select fbx for unity just like we did for the character and then you can download it with the skin or without the skin so if you select with skin then it will also download the character that we selected so in our case we have already downloaded the character so we don't want to download that again so i'll set it to without skin all right and then for the frames per second leave it at 30 and leave the keyframe reduction at none all right so make sure these settings are right and then click on the download button to download the animation as an fpx file so i'll just name this idle and save it okay so next we need a blocking animation so let me search for walking and again we have lots of variations let me try this one all right this one looks okay so for the walking animation make sure to check the in place check box all right so once we check that the character will only play the animation she won't actually move while playing the walking animation all right so 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 right we wrote the code for it in the previous video so be sure to check the in place check box 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 so let me just name this one walk and finally we need an animation for running so 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 so now i'll go ahead and download this so i'll call this one run all right so now we have the animations so let's go ahead and import them to unity so in unity in the assets folder i'll create a new folder called animations and then i'll import three animations that we downloaded right now okay so now you can check if an animation is working by selecting the animation and then selecting the animation tab and at the bottom you should be able to preview the animation but right now it says we don't have a model and we have to drag a model to this preview area so let's go ahead and drag our model into the preview area of the animation all right so now if we 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 miximo right so the problem is if we bring in another model to a project the animations might not work on them so let me show you by importing another model all right so this is another character model that i downloaded from miximo so 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 as you can see that when i press the play button the animation is not playing on the character so these animations won't work on other characters so 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 unity has an easy solution for this so before we look at the solution let's look at why the animation is not working on different models in the first place so 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 and now if you look at the second character it also has bones but the problem is the names of these bones are different right so 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 so if you expand the walk animation you can see the animation clip over here and if you double click on it it'll open the animation clip in the animation window so 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 and here you can see that this animation uses the bone names of this character right the board names of the viper character is different and that's why the animation is not working on the y bar character so if you rename all the bones of the y board character and make it as same as this character then the animation will also work on the whiteboard 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 so the good thing is unity provides us with a solution in which we can solve this with just few clicks so the solution is humanoid retargeting so 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 so we'll do that for all the characters and all the animations and once that's done the animations will work with all our characters all right so let me show you how to do humanoid retargeting so for this first we have to select the character and then you have to go to the trick tab and in here you have to change the animation type from generic to humanoid all right so this works by creating an avatar is a thing that maps the bones of a character to the standard set of bones so in the avatar definition we have to select create from this model and then all you have to do is hit apply all right so you can see the tick mark over here so that means unity was successfully able to map all the bones in case unt was not able to map it automatically then you'll have to click on the configure button and this will show you all the mappings that were done by unity all right you can see that over here so if some bones are missing from the mapping then you'll have to manually drag and drop it over here all right so i'll click on the done button to go out of the avatar and you can also see it over here so this is my character and inside it we have the avatar now all right so now we should also change all our animations to humanoid so let's go ahead and do that so first let me just select the work animation and in the rig tab i'll change this to humanoid and then for the avatar definition we have to select copy from avatar in the case of animations and then we have to select the avatar that we created earlier all right so let me go ahead and assign that avatar and now we just have to hit apply all right so we have to do this for all the animations we have to make them humanoid so let me select the other two animations and also make them a humanoid animation alright so now the animation should work on our erica character all right and then it'll also work on the vybot character if we turn it into a humanoid so let's go ahead and do that so in the rig tab i'll change it to humanoid and since this is a model i'll select create from this model for the definition and then i'll hit apply all right so it was successfully able to create the avatar and map the bones so now the animations should also work on the vibe character so let's go to the animation tab and preview the animation on the vibe character okay so the animation is working fine so 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 so next 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 alright so here at the bottom of the player's feet you can see a circle and the circle is moving right so if the circle is moving that means the animation has some kind of 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 so we have to get rid of this motion and by the way if we drag our other character the main character that we are going to use so here also you can see the circle is moving so 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 the sword 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 so the problem is when we turn our character into a humanoid character it will automatically set up the root motion so that's what's causing this motion in the animation all right so we can easily fix this by using these three options so here for the root transform rotation root transform position by and 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 bake into post for all of them all right so now you can see that the circle is not moving anymore it's stationary so 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 back into pose for all three of these and then also change their based upon to original all right so i'll go ahead and hit apply so now the circle is stationary so 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 so we'll have to do it one by one so first let me do it for the run animation all right so i'll check back into pose and change the based upon to original for all three row transforms all right and then i'll hit apply and by the way we also want these animations to loop so let me also select loop time and loop pose to loop these animations while we are here all right and now let me hit apply so now let me do the same for the idle animation all right and let me also check loop time and loop pose so that the animation will loop all right and finally let me also turn the loop time and do pose for the walk animation so now we are done with the setup of our animations so next we can use these to animate our character when moving so your character movement will look like this once you add animations so let's look at how to do this so we'll play the animations on our character we have to create an animator controller so let's go ahead and create that so in the assets folder i'll create a new folder called game all right so this is where i like to put all my prefabs and scriptable objects and animator controllers basically all the things that a designer would want to use so inside this folder i'll create another folder called animator and i'll create my animator controller over here so in create you can see animator controller so i'll name this character controller okay so now we can double click on it to open the animator controller so animator controller controls what animation should be played on our game object so we can drag all our animations in here and then define what animation should be played based on the parameters so let me drag one of the animations in here so i'll just drag the run animation so let me rename this to run so the first animation that you drag into the animator controller will be the default animation that will be played so if i also drag the other animations you can see that their color is different only their own animation is in orange color right so that's because this is the default animation so now if we attach our animator controller to our character then our character should play the run animation by default so to attach an animator controller to the game object we have a component called animator all right and in this component we can specify which animator controller that we want to use so i'll assign the animator controller that we created and then we also need to assign the avatar of the character so the avatar of this character is called erika archer of the so let me assign that so now when we run the game our player should play the running animation all right so you can see that it's working fine so 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 so on the y board character it already has an animator component attached to it so unity dust is automatically when you turn a character into a humanoid character and also over here you can see that the avatar has automatically been assigned okay so we just have to assign the animator controller and the y bot character should also play the running animation all right so it's also playing the animation so our animations are working fine on all the characters so 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 right so 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 so the animator controller there are different ways to control what animation should be played but in the case of moment animations i want the animations to blend smoothly so for example instead of just switching from the walk animation to the run animation i want to blend between them based on the speed so to achieve that i'm going to use a blend tree so let me go ahead and delete these three animations all right and now i'll create a blend tree to blend between our animations all right so i'll name this planetary locomotion and then we can double click on the blend tree to open it so here 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 so in our case we want to add three animations so 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 drag and drop the xpx file of the animation here we can only assign the animation clip to it all right so we have to assign this animation clip so the first field we have to assign the idle animation and then to the second field we have to assign the block animation all right and finally to the third field we'll assign the run animation okay so 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 and at point five it'll play the walking animation in the actual speed of that animation right so that's because here we have thresholds so threshold of idle is 0 walking is 0.5 and running is 1. all right so when it's at 0 it'll be in the idle animation when it's at 0.5 it'll be playing the walking animation and when it's on it'll be playing the running animation all right but the cool thing here is when the blend is between 0.5 and 1 it'll play a fast walking animation like this so this is a blend between our walking and running animation so this is why blendtree is really useful and also if i try setting the blend somewhere between 0 and 0.5 then it'll also blend between the idle and the block 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 animations blend the blending between the walk and the round animation that is really useful and by the way you can also change the threshold of different animations so right now it's not editable because the automate threshold checkbox is turned on so if you turn it off then you can edit the threshold values so 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 so this is just a personal preference which you can play with this value and set it to one that you like based on how you want your third person controller all right so now we just have to set this blend parameter from the code and the character should automatically play the correct animation all right but first let me actually rename this blend parameter to something meaningful so i'll call this more amount so that makes sense right if the amount is 0 then the character should be playing the idle animation then as we increase it the character should start walking and running right so now let's go ahead and set this parameter based on the character's movement so let me open the player controller script okay so to set a parameter to the animator first we need to get a reference to it so i'll cache the reference to the animator from the awake function i'll just use the get component function to get the reference of the animator so now we should set the mo amount parameter in the animator so we are already calculating a value called move amount over here so we can set the same value to the animator so to set a value to the animator picking car animator dot set so when you type set you can see that we have lots of options so in this case the mo amount parameter is actually a float value right so here we have different types of parameter more amount is actually float as you can see that its value is floating point so to set the move amount from code we can use a set float function so in the first parameter we should provide the name of the parameter that we want to set so in this case the name of the parameter is mo amount and then in the second parameter we should pass the value that we want to set so in our case we are already calculating the value over here so let me just pass that as the second parameter okay and by the way one thing i want to address is the move amount parameter should be between 0 and 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 between zero and one to make sure that the animations are selected correctly all right so to clamp a value between zero and one we have this function called clamp zero one all right we just have to put the value in this function like this okay so now our character should play the animation correctly based on our moment so let's go to unity and test that and 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 so 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 up the animations but if you look at how the animation stops it's stopping really fast right it doesn't look very realistic so the reason for that is because when we start pressing the input the more amount becomes zero immediately and and the more amount of zero the character will start playing the idle animation immediately so we can easily make this smoother by adding a damping when setting the move amount so if you look at the third parameter of this function you can see that we have a parameter called dam time so if we add this parameter then the animator will smoothly change the parameter to this value instead of setting it instantly all right so for the damn time i'll pass a small value like 0.2 and then when we pass the damp time then we should also pass the delta time in the fourth parameter so i'll pass time dot delta time in the fourth parameter okay so this should smooth out the animations for us so let's go to unity 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 -10 all right so now the camera won't go beyond this point okay so yeah our third person controller is looking pretty good so there is one thing i missed to do while setting up the animations so if you look at the idle animation as you can see that it is eight seconds long and has 250 frames so 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 so having such a long animation can cause problems for us in the future when we transition to other animations so we can make this shorter by reducing the end frame we can just drag the slider to reduce the end frame so i'll just make the end frame 30 all right so now the animation is only one second long so let's apply the change and let's just just to make sure that everything is working fine all right so things are working just like before so next we look at how to set up collision and gravity for our character so 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 so now if we try walking through this cube as you can see that we don't have any collisions so we need to handle that so to handle collisions we have two options we can either use a rigid body or we can use a character controller so for this project i'm going to use a character controller so let's look at the documentation of the character controller to understand what it does so in the docs you can see that the character controller allows moment constrained by collisions and it is not affected by any external forces so this is an important point if we are using a rigid body it will be affected by external forces so we don't want that for the player in our game that can cause problems in the future so we are going to go with a character controller instead of rigid body all right so let's go back to unity and let's add a character controller to our player game object so let me search for character controller alright so now in the scene view you can see that there is a capsule collider so the character controller comes with a collider and we can adjust the size of the collider by changing these values so i'll change the height to something like 1.7 since that's the height of our character so next we need to add an opposite in the y so that the collider fits the height of the character so usually i like to set the y a little above the half of the height so the half height is 0.85 so i'll increase it a little and make it 0.9 all right so this will make sure to keep the players feet grounded so 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 and one more thing i like to do is i like to add a little z offset somewhere around 0.08 so the reason for this is because our player will always face the direction in which it is moving so collisions will mostly happen in the front side of the player so i like to offset the collider towards the front side alright so we have set up the character controller so 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 so that will make sure to constrain the movement by collisions so we should use character controller.move function instead of this so first let's get a reference to the character controller all right i'll cache a reference to it from the awake function okay so now to move the character i'll use character controller dot move function and for the motion vector we can pass the same value as before so let me just cut that and paste it over here all right and i can get rid of this line so this will move the character just like before but it will also constrain the movement by collisions so now let's go to unity and test if the collisions are working okay so now you can see that we can run to the cube all right so the collisions are working fine so next we should handle gravity and make the player fall when the player is in the air so 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 and she can basically walk in the air all right so the character controller is not affected by any forces like the gravity so we have to manually apply the gravity to our player from the player controller script so 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 only make the player far if the player is in the air so the character controller has a field to check if the player is standing on the ground or not so the name of the field is is grounded so this will return true 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 so i don't like using this i like to manually check if the player is in the ground or not by using physics so if you look at the implementation of third-person controller in unity starter assets you'll see that even in this project they are not using the is grounded property of the character controller instead they are checking it manually by using physics so let's also check that manually by using physics so let me get rid of this line all right and below the update function i'll create a new function called ground check so from this function i'll use the physics dot checkspear function to create a small sphere at the player's feet and check if there are any colliders overlapping in that sphere okay so here you can see the description of this function it'll return true if there are any colliders overlapping in the sphere that we defined okay so to create the sphere we have to pass 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 are doing any physics operations it will 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 so i'll define serialized field variables for these three values so that we can control them from the inspector all right so first let me define a variable for the radius of the sphere so i'll call this ground check radius okay i'll set it something like 0.2 by default so 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 so i'll create a vector for the position offset all right let me call this ground check offset so next we also need to define a variable for the layer mask that we need to check so i'll create a layer mask over here and i'll just call it ground layer okay so now in the shakespeare function for the position we can pass transform dot position but we also need to add the offset right so what we can do is we can transform the offset point based on the player's current position so we have a function for that called transform point so what this will do is this will transform the position from the local space to the world space and it will transform it relative to the transform that we are using here okay so in this case it will transform it related to the player so i'll call transform point and for the point i'll pass the ground check offset okay so we have passed the position so 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 so let's actually create a variable to store the value of this function so here i'll create a boolean variable called is grounded okay and i'll store the value returned by this function into this 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 is grounded variable okay so let's actually use a debug.log so that we can test if the player is grounded or not okay so next i'd like to visually see the spear in the scene so this will allow us to set the offset and radius properly and also if there are any issues with the ground check it'll allow us to understand what's happening so we can achieve that by drawing a gizmo so guess most of the shape that you see in the scene so for example if you select the player you can see the collider so that's actually gizmo so we can draw a gusmo like that for the ground shakespeare so to draw a gismo we can do that from two function the first one is on drug is most and the second one is on drug is most selected so androgynous selected will only draw the gizmos if this game object is currently selected so let's use that so we can draw a gismo by calling gizmos dot draw sphere function all right so for the center we can pass the player's position after by the ground check offset and for the radius we can pass the ground check radius okay so this will draw the gizmo so we can also specify the color of the gizmo by setting the color before the draw function so i'll set gizmos dot color so i want the color to be something like a green so in the rgb value of the color i'll pass zero for red one for green and zero for blue okay and i'll 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 checks here when we select the player in the scene okay so you can see that it's drawing the ground shakespeare so let's adjust these values 0.2 is okay for the ground checked radius and for the ground check offset i like to put the y value at half of the radius so i'll make it 0.1 all right and i also like to give a little bit of offset in the z so that the spear covers the feet so around point zero seven should be fine all right so now the spear covers the feet of the player so next we need to assign the ground layer so what i'll do is i'll add a new layer called obstacles so all the obstacles like the ground and this cube over here all those will be in the obstacles layer all right so let's go assign the plane to the obstacles layer and i'll also assign this cube okay so now for the ground layer we can just pass the obstacles layer all right so that's all we have to do so let's go ahead and check if the ground trick is working all right so right now since the player is in the air you can see that this grounded value is false but if i go to the scene view and [Music] bring the player down to the ground you can see that it becomes true so our ground trick is working properly so now we know if the player is grounded or not so next if the player is not grounded we should apply the gravity and make the player fall right so 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 so 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 so the first thing i'll do is i'll move this line out of this if condition the reason is because the vertical moment 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 so i'll move outside if condition and then what i'll do is i'll put the movement vector in another variable called velocity so let me define velocity over here all right and then we can use the velocity variable over here so now we can also set the y component of the velocity if the player is falling right so if the player is not grounded then we can apply a velocity over here to make the player fall down and 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 so if you say a car is moving at 40 kilometers per hour that's a speed but if you say it's moving at 40 kilometer per hour in this specific direction then that is the velocity so it's just a speed with the direction all right so we have to set the y component of the velocity to make the player fall so 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 so to be more accurate every second the speed of the object will increase by the gravity so we can't set a constant value here for the y velocity we need to keep increasing it so 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 card y speed all right and then if the player is falling then we should keep increasing the y speed by the gravity right so if the player is grounded we don't want to do anything now we want to increase it if the player is falling right so we want to increase it from the else part of this condition okay so 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 dot gravity property and we only want the y component of the gravity so i'll just get the buy so this value is actually set from the project settings so if you go to edit and select the project settings in physics you can see that we have gravity so this is where the gravity of the game world is set all right so here if the player is falling we want to increase the buy speed by the gravity but we should also multiply this with time dot delta time so this is because the y speed should increase by the amount of gravity every one second right but the update function is not called every one second it's called multiple times in a second right so 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 so now we are increasing the y speed if the player is not grounded so let's set the y speed to the y component of our velocity all right and then if the player reaches the ground and its 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 minus 0.5 so the small value will make sure to stick the character controller to the ground all right so this should make the player fall down if the player is not in the ground so let me just get rid of the debug log and let's go ahead and test if the player is falling all right so you can see that the player fell down so the gravity was applied correctly so let me also try placing the player out of this box just to test how it falls from such objects all right so first we'll fall to the box and 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 so 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 z 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 so next i just want to organize the player controller inspector a little so i want some segregation between the speed variables and the ground check variables so we can easily do that by adding a header above the ground check variables so let me add the header attribute and i'll just call this ground check settings okay so 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 block animation when she's falling we'll be fixing those in the future but right now this is a good start so next let's set the skin with property of the character controller so this is a really important property so if you go to the documentation of the character controller and if you switch to the manual so the manual will have more detailed explanation when compared to the scripting api so here we have a detailed explanation of all the properties so if you look at the skin with skin width allows other colliders to penetrate the character controller a little so this is used to reduce jitter and it also prevents the character from getting stuck so unique recommends setting this to 10 percentage of our radius so in our case the radius is 0.2 so the 10 percentage of 0.2 will be 0.02 all right so i'll set the skin with 2.02 so next we should change the y of the center based on the value of the skin width so earlier i told you that the wire should be a little above the half of the height for the characters feet to be on the ground so if you want to be more accurate we can set the center to half of the height plus the skin width all right so half of the height is 0.85 and the skin width is 0.02 so if we add that we'll get 0.087 so 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 so next we'll set up controller input so that we can control the player with joystick so if you connect the joystick and test the game you can see that we are able to move the player using the left analog stick but we are not able to control the camera rotation using the right analog stick all right so if you look at the player controller script here we are using the horizontal and vertical input to move the player so unity automatically sets up the horizontal and vertical input for the joystick so that's the reason why we are able to move the player with the joystick so you can actually see the input setup 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 so here we have horizontal and vertical and over here we have another horizontal and vertical input right so they are defined two times so the first one is defined for the keyboard so here it uses the left and right keys and the second one is defined for the joystick all right here it uses the x-axis of the joystick so like this we should set up all our inputs for the joystick so we won't be able to control the camera using the right analog stick right so if you look at the camera controller script right now we are just using the mouse x and mouse by input for controlling the camera so instead of this we should set up a new input over here and we should set it up for both mouse and joystick so here i'll create two new inputs called camera x and camera y so i can just duplicate this mouse by input to create a new input so we can right click and select duplicate array element all right and i'll name this as camera x so we want this to be controlled by the mouse we'll create another one for the joystick so here the type should be mouse moment and i'll change the axis to x axis because this is camera x all right so now we can just duplicate the camera x and we can create camera y so here the axis should be y all right so next let's create camera x and camera y for the joystick so i'll just duplicate this camera y element let me rename it to camera x and the type of this one should be joystick axis and for the axis we'll select the fourth axis so the fourth axis is the horizontal axis of the right analog stick all right so now in case of joystick we also need to tweak a few settings over here so let's look at how the left analog stick is set up for the horizontal input so here you can see that the sensitivity of the input is one and for the value of the debt they're using 0.19 so we can also do the same for the right analog stick for our camera x input so i'll change the sensor to d to one 0.1 will be a perfect value for mouse but it'll be really low for analog sticks so let's change this to one and we'll also change the value of dead to 0.19 so this will be the dead zone if the value is below it then it will be mapped to zero all right so we have set up the camera x input for the joystick so next let's duplicate this and create the camera y input all right so the y axis of the right analog stick is the fifth axis so let's change the axis to fifth axis all right so that's all we have to do so now we have a new input which can be controlled by both the mouse and the joystick so let's use this input for rotating our camera so the camera controller script instead of using mouse x and mouse y we'll use camera x and camera y all right so 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 so now i'm also able to rotate the camera by using the right analog stick okay so now we can also control our third person controller using a joystick so now we have a pretty decent third person controller and the best thing is we build this from scratch without using any assets so congrats on reaching this far if you want to build on top of this and create a more advanced controller that can perform barco actions like this then check out our unity third person parkour system course on udemy i'll put a link in the description if you want to get it for a discounted price so i hope you found this video helpful thanks a lot for watching and i'll see you in the next video
Info
Channel: Game Dev Experiments
Views: 24,537
Rating: undefined out of 5
Keywords: unity third person controller, third person controller in unity, unity character controller, unity camera relative movement, unity animation retargeting, unity root motion, unity ground detection, unity third person camera, unity third person movement
Id: DXw9QhsjlME
Channel Id: undefined
Length: 111min 35sec (6695 seconds)
Published: Tue Jul 12 2022
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.