[#1] FPS Character Controller Tutorial [Godot] | The Basics

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
[Music] i've had a few questions about the movement system in spring and fall and while i could just release the source code for this system i'm actually far more interested in teaching and i guarantee you're going to get a lot more out of writing a system like this yourself and understanding what goes into it one of the biggest hurdles in getting into 3d game development is the need to understand linear algebra that's why if you're new to game development it's probably better for you to start with 2d in this tutorial series i want to go through some of the key concepts that went into my movement system in spring and fall and use this as a way to teach you some of the fundamental linear algebra concepts you're going to need if you want to make 3d games we're going to cover things like transforms bases 3d rotation vector math and probably more while the system was built with godot these concepts are global so they will come in handy even if you're using something like unity or unreal so grab a tea or coffee and let's get into it so i've started a new project in godot and i just want to mention that if you're new to this engine or game development in general i have put some resources down in the description for you to check out before you watch this tutorial this is kind of geared towards people who have used godot before maybe you've made 2d games in the past and you want to transition to 3d in that case this is a good tutorial for you but if you're new to godot i would recommend starting somewhere a little bit simpler with that out of the way let's start by creating a 3d scene and i'm just going to call this world i'm going to make a little room for our player to run around in so first i'm going to create a mesh instance and over here in the mesh we're going to select cube mesh and up here on the mesh button there is a option called create try mesh static body if you click that it's going to create a static body with a collision shape which matches the geometry of the mesh instance so now that we have a collider our player should be able to collide with this and recognize it as a floor so we're going to go ahead and resize this down i'm going to make it a little bit bigger and i'm also going to go ahead and change the color of the material so i'm going to create a new spatial material i'm going to make it gray and i'm going to save this so that i can use it for the other cubes cube i'm going to essentially repeat that process to create some walls okay it doesn't have to be perfect this is good and i'm just leaving one space open so that we can test the gravity later on the other thing i'm going to do is add a light just so that we can see things a little bit better get out of here okay awesome i'm going to go ahead and save this and call it main now what we want to do is add a player so i'm going to go ahead and hit ctrl a to add a kinematic body i'm going to save this as a new scene called player and we're going to hit this button to edit it called player you can see that it is getting upset with us because it doesn't have a collision shape so let's go ahead and give it a collision shape and the most obvious choice here is a capsule shape now you'll notice that the capsule is orientated the wrong way so we're going to go ahead and rotate that so that it is vertical and change the radius and height to something like 0.8 and 0.2 i'm also going to add a mesh [Music] with the same dimensions just so that we can see what's going on here we're going to line that up where y equals zero it doesn't have to be perfect the next thing we're going to need is a camera so i'm going to go ahead and create a spatial node first this is going to act as a sort of pivot or root node for our camera i'm going to call it look pivot and i'm going to move it to roughly where the head would be and then we're going to add a camera on top of that so you will notice that the camera is actually facing the opposite direction to this blue arrow if you're not familiar with how the axes work this is the z-axis this is the x-axis and this is the y-axis you can see in the top right that is showing the world space um coordinates there where the arrows are is the positive of each direction so this is positive x this is positive z and this is positive one i like my camera to be facing positive z so i'm going to go ahead and just rotate this to be 180 degrees if we go back to main i'm going to rename this player here as well and we hit play we are going to have to select a main scene so go ahead and select main and you can see that the camera is actually displaying our scene which is very good i am also going to make these walls just a tad taller so now that that initial setup is done we get to start writing code which is my favorite part we're going to attach a script called player.gd and let's get rid of all of the existing things in the ready function we're going to do this input set mouse mode input dot mouse mode captured all this is going to do is hide our mouse cursor so if i hit play you can see that my mouse cursor disappears the first thing we're going to do is allow our player to look around with the mouse if i go back to the 3d view here is how we're going to do it when the player moves the mouse left to right we want to rotate the entire player object along this axis here so that we change the way that the player is facing however when the player moves the mouse up or down we don't want to be rotating the entire player we just want to rotate this look pivot option so that they look up or down without rotating the player itself so now that we know what we're doing let's go ahead and write the input function this is a built-in function which allows us to process input events so we want to check if the event is mouse movement so we gonna write this condition if event is input event mouse motion if you look at the godot docs you can see there's a bunch of different information here about all these different input events that you can process in particular we are interested in this relative property the mouse position relative to the previous position this essentially is going to give us how much the mouse position has changed since the last frame in particular event.relative.x is going to be our horizontal mouse movement as i said before we want to rotate the player like this according to the horizontal mouse movement now you can see that this is rotating around the y-axis so we're going to do rotate y degrees 2 radians event dot relative x now it should be noted that we are going to have to do -1 times event relative dot x simply because of how event relative x works we can define a constant for the mouse sensitivity and i'm going to set that to be 0.2 and we're going to multiply that by the mouse sensitivity so if i hit play you can see i can now move my mouse around and we are looking to the left and right as expected if you're still curious about this negative one let me try and explain it really quickly if you look in the bottom left you can see that rotating to the right is equivalent to rotating minus certain degrees and rotating to the left is rotating in the positive direction event relative x goes up when we move the mouse to the right so we have to multiply it by negative one so that when we move the mouse to the right we're actually rotating in the negative direction as expected now we can do vertical movement so event dot relative y is our relative vertical movement of the mouse and what we're going to do is we're going to rotate this look pivot object based on that value so we need a reference to that object on ready var look pivot equals look pip if you're unfamiliar with this syntax it is shorthand for get node look pivot i also like to use type hinting here so that the editor knows what type everything is [Music] so we want to rotate our look pivot but we're going to use rotate x you can see that this is the x-axis here and we want to rotate it vertically like so so look pivot dot rotate x event dot relative dot y and as before we're also going to need to wrap that in degrees to radians and we're also going to multiply by the mouse sensitivity let's hit play i can look up and down fantastic there is one small problem with this if i keep looking up oh there's nothing that stops me from doing a crazy backflip and now i'm back up the right way to fix this we simply need to clamp the rotation values between negative 90 degrees and positive 90 degrees so look pivot dot rotation dot x equals clamp as the name suggests this function clamps a value between a minimum and maximum so let's say my value was five and my minimum was zero and my maximum was 2 this would return 2. hopefully that makes sense we're just making sure that the value in the first position is between minimum and maximum so we want to clamp the rotation x between negative 90 and positive 90. so now you can see i can't actually move or look further down or up than 90 degrees now that we can look around it's time to start implementing movement and this is where i get to tell you about transforms and bases first we're going to need to create some input maps for forward back left and right forward will be w back will be s left will be a and right will be d since we're going to be using physics we need to write the physics process function if you're not familiar with this this is a function that is executed every physics frame since we're moving the player and using physics we need to execute all of our player movement inside of this function the delta argument is the time in seconds since the last physics frame and we can use this to normalize things so that the behavior is the same regardless of the frame rate i'll explain more about that later just ignore it for now the first thing we want to do is get a input direction based on what the player is pressing so i'm going to write a function for this but in the meantime let's do var input direction equals get input direction so the get input direction function is going to spit out a vector 3 with the direction of the input that the player is currently pressing i'm going to create this var called z which is going to be the input action strength for forward minus the input action strength for backwards let me explain what this is doing if i'm holding down the w key this action strength will be equal to one if i'm not it will be equal to zero the same is true over here so if i'm holding w and i'm not holding s this entire value will be one if i'm holding s and i'm not holding w this entire value will be negative one if i'm holding both at the same time the value will be zero so i won't have anything in my z-axis this is exactly what you'd expect and also this action strength is a really good function for input movement because if you end up implementing controller support the action strength will change depending on how hard you're pressing down the joystick if you're pressing it all the way forward then it'll be one but let's say you press it only halfway forward then it will be 0.5 that way you can implement dynamic walking speed but let's not worry about that for now we're going to do a similar thing for x so the x variable is going to store a value which is one if we're moving all the way left and negative one if we're moving all the way right let me quickly go back to the player to show you why i've chosen these exact directions if you look in the top right this shows our axes and you can see that positive x corresponds to my player moving left now we can combine this into a single vector by writing return vector 3 x 0 z the y value is always zero because we're not moving up and down just yet we're going to save that for when we jump i want to point out that this is actually not quite correct we're going to have to come back and modify this but i'm doing it on purpose so i can explain something to you in a second now that we have the input direction we can use the move and slide function to move along the input direction and we have to give it an up as well so that it knows what a floor is what a wall is and so on we're also going to multiply this by some move speed so let's use three but i'm going to define a constant for that so constant move speed let's hit play and see what happens so now in the game if i hold the w key i move forward and if i hold the s key i move back similarly if i hold the a key i move left and d moves me right one thing that i forgot to do was normalize this vector we want this vector to always be of length one to explain what i mean if i don't have the normalized there and i hold w and d at the same time i'm actually going to be moving faster than i can if i just hold w that's because this will be one and this will be one so the overall length of the vector is actually going to be greater than one so we wanna make sure that we normalize this vector so that the speed is always consistent the only issue is if i look to the left and hold w i actually end up moving to the right and if i hold s i end up moving to the left whichever way i look w is always moving me towards the open end of the box this has to do with the difference between world space and local space let's say i've rotated my player to look this way the world space z axis is still pointing that way but the local space z axis is pointing forwards relative to where the player is facing so i don't actually want to move along the z-axis for the world space i want to move along the z-axis for the player space this is where transforms and bases come in the transform object stores information about the position rotation and scale of an object you can see the transform information here in the inspector the basis refers to just the rotation and the scale information essentially we want to use the basis of the player to figure out how the z-axis for the player corresponds to the world coordinates for example if i'm facing this way the z-axis for the player is actually corresponding to the x-axis for the world imagine we're looking at the world from the top here's a diagram the world space has z always moving up and x always moving left but if the player is rotated this z-axis no longer corresponds to the world space z axis the player sees this vector as zero zero one that is x is zero y is zero z is one in world space this vector would actually correspond to something different it would probably look more like this don't worry about the exact numbers here but the point is it would be negative on the x direction and positive in the z direction so we need some sort of function which will convert this vector in the player space to this vector in the world space information we need to do that is stored in the player basis if you go to the basis documentation you'll see this little magic method right here and the description is short but sweet returns a vector transformed by the matrix let's actually write the code so you see what i'm talking about what we can do is we can get the transform of the player get the basis associated with that transform and just put this vector into the x form function what it's doing is it's taking this vector and actually multiplying it by the basis matrix for the player what that does is it converts it from player space into world space now if i look to the left and hold w i'm actually moving where i look let's finish up by adding gravity i'm going to define a constant for gravity acceleration and that's going to be 9.8 units per second i like to break up my movement into different components that allows me to have fine grain control over all of the different vectors that are having an impact on my player movement so i'm going to put in our input move as a vector here for now we're just going to have the two we've got the input movement and we've got gravity and i've put this as gravity local because this is actually going to change depending on what the player is doing we can refactor this so input move equals get input direction times by move speed and in move and slide we're going to have our input move plus our gravity local these are the two different components that impact how our player moves right now now all we have to do is actually define what the gravity local is to start with let's check whether our player is on the floor or not if we're not on the floor we want the gravity local to increase by gravity acceleration times vector 3 dot down we are missing one component here and that's the delta so let me explain really quickly if you don't know what the delta is why we need to use it here let's say we're on a really high end machine and our physics frame rate is 60 frames per second that means the delta is going to be 1 over 60 and this function is going to be called 60 times per second that means that in one second the gravity local is going to go up by 9.8 60 times however if our frame rate was only one frame per second then in one second our gravity local would go up by 9.8 only one time what that means is that the strength of the gravity is actually going to change depending on the frame rate that we're playing at that's definitely not something we want so what we do is we multiply by delta hopefully you can see kind of how this helps us if the frame rate is really high then delta is going to be very small because the time between frames is very small on the other hand if our frame rate is very low delta is going to be very high so it's going to compensate for the frame rate we don't need to multiply by delta for the move and slide function because the movement slide function actually does that for us you can read that in the documentation now if i walk off the edge you can see that i fall to my doom adding jumping is relatively easy let's add a jump action and map it to the space key if input action just pressed jump we change our gravity local to be equal to vector three dot up times some jump force let's just define our jump force here and i'm going to use three what's happening here is if we press the jump key on that frame we're going to change the gravity local to be equal to up times three we don't need to multiply by delta here because this should only execute once on the next frame we're not going to be on the floor anymore and so the gravity local is going to start kicking in if i hit the space key you can now see i do a cute little hop there is one final thing that i suggest we add if we are on the floor we can use this equation to make sure that gravity is pushing us towards the direction of the floor the floor normal is the vector that is pointing up from the floor if we take the negative of that it's pointing down towards the floor this will come in handy when we're dealing with slopes if we're walking up a ramp gravity is going to push us towards the ramp so that we don't keep sliding down okay so that's all for this episode if you're new to 3d game development that was probably quite a lot of information for you to digest so i would recommend maybe re-watching some parts of it or leaving some questions down in the comments below i also have a discord server the link is in the description feel free to join that and ask questions to me directly i will be very active on that server and happy to help you out also please do let me know if you want to see more tutorials i can go into grappling hooks and launching but only if people are actually enjoying the tutorials that being said i really hope you learned something please consider subscribing if you want to see more otherwise i'll see you next time
Info
Channel: Dillon Steyl
Views: 4,915
Rating: undefined out of 5
Keywords:
Id: 8-198msNlGg
Channel Id: undefined
Length: 23min 0sec (1380 seconds)
Published: Tue Aug 10 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.