Cinemachine First Person Controller w/ Input System - Unity Tutorial

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
in this video i'll be going over a first person controller that you can use with cinemachine and the new input system so you can walk around you can look and it will go in the direction that you're looking in all right so let's get started so i just opened up a brand new project of erp and i'm just going to be using this scene here since it has some stuff in it and the first thing we want to do is go to window package manager and we want to install cinemachine so make sure you're in unity registry and not in any of the other ones or else you won't be able to see the package and let's download cinemachine so clicks in a machine here and click install down here and once that's done let's search for the new input system and click install on that as well and it will ask you to restart the editor and we just want to click yes so right here click yes to restart the editor alright and now that that is done let's go into our scripts folder and make the actual input system controls so that our player can move so let's right-click and create a new input action and let's call it player controls all right so now we have our input action so the first thing we want to do is add in a action map so we can click this plus button and add in an action map so in this case i'm just going to say player and an action map you can use it for different controls for different occasions so you can switch between different maps depending on a player location for example if you're in water you'd want a different set of controls than if you're on land but for now we just only need one of them so i'm gonna name it player then for our action this is our actual control so we want to do a movement action the other action we want is a jump action and finally we want a look action which is our mouse looking around so for our movement we have our action type we want it to be a pass pass-through or a value either will work and then the control type has to be a vector 2 because we're using wasd or arrow keys whichever one you prefer all right and then you can add in a binding for the controls with this plus button here and there's an edit binding and an added 2d vector composite so we want to add the 2d vector composite and we want to call that wasd or movement keys whichever you want so the 2d vector composite will return a vector 2 and you can input the values for what you want for up down left and right and it will return the vector 2. so for example on the x axis it'll return negative 1 if you're pressing the left key and it will return 1 if you're pressing the right key same with up and down but for the y-axis so you can actually set the controls here in the path you can click listen and press w and press the keyboard one down listen press s left listen press a and then right listen press d and for the jump we can keep it as a button since we're only going to be pressing the space bar and then you can add in a space bar so we can listen to our space bar and finally for our look it's also going to be a vector 2 since when we look around we look around the screen the mouse is moving in a vector 2d space so it's moving on the x and y plane so we can go to pass through and we can click vector 2 for that we don't need to add a 2d vector composite because we don't want four separate values instead we can go into the path here and click mouse and then we have some several options here so we want delta because the delta returns the difference between our current position and our previous position in the last frame and we want that because we want to be able to look in the direction that our mouse is moving in alright so all we have to do now is click save asset and then we can click our input action and let's generate a new c-sharp class and click apply this is what it looks like when it's generated it's just a bunch of data we don't need to change that and we shouldn't change that so let's actually make a new script create c-sharp script and let's call it input manager and so we actually have to initialize the player controller and so here we'll initialize our controls so that we have a centralized place where we're initializing it so we can initialize it by saying private player controls player controls and then in our awake function we can say player controls equals new player controls we also have to have an on enable function and here we can say playercontrols.enable so you have to make sure to enable your controls and we also have to disable it so on disable we can say playercontrols.disable so here we'll have some helper functions so that other scripts can call these helper functions and those scripts don't need to instantiate the player controls themselves so let's have a helper function for each of our movements so let's do movement so that returns a public vector 2 get player movement and we can just return playercontrols.player and we have to do dot read value and we have to read in our vector2 and let me copy this paste it down here and instead this will be called get mouse delta instead of movement we want to return our look and for the last one we can say public bull so this returns a boolean and this will call player jumped so this will return true if the player has jumped on this frame we can also name it player jumped this frame and here we can just say return playercontrols.player.jump and then here we have a nice value called triggered and that returns true if the control was triggered on that frame all right that script is done on to the next script the next script is our player controller so we want to right click create c-sharp script player controller and so we're gonna use a player controller that unity actually provides to us so right here you can see under charactercontroller.move we're actually gonna be using the character controller that unity has and right here they have a script that we can just copy that uses the character controller and it does all the nice stuff for us so let's actually copy that script i'm just gonna paste it in here and this will be in the description the link for that all right so we have our character controller right here private character controller and we do add component character controller um i'm going to change this because i actually want to put it in manually so we're going to get our component character controller and we don't need the game object in front of it player velocity is just our velocity on that frame this will return if our player is grounded and these are some variables that you can set in the inspector so you can do a serialized field on each one of these so you can see them in the inspector and i'm just going to move those to the top all right so let's go over this really quickly so first we have is our character grounded and it queries the controller to see if it's grounded if it's grounded and we're not moving downwards then set the velocity to zero and right here you'll see that we'll be doing the jump later on so first they do the horizontal movement so moving on the ground so here they get the input get axis horizontal and vertical this is the old input system and then they move the controller with move times time delta time and then times your speed and so that's one action and so now this is the jumping action and this actually rotates the player so we do gameobject.transform.forward equals move so it rotates the player in the direction that it's moving in and then this is actually the jump so if we are pressing on the jump and we're grounded then do some physics and here we're adding in our gravity and then here we move the controller with our player velocity.y that we calculated and so we're going to be changing this a bit so we can go with our new input system so first of all we want a reference to our input manager so in our player controller we can do private input manager and we can just call it input manager and so we're supposedly only going to have one of these input managers on the scene at all times so we can actually make this a singleton which is a static class meaning we'll only ever have one instance of this so we can say private static input manager and we can say instance and so this is just keeping track of our instance so now that we're keeping track of our instance we actually need to return our instance whenever we call this class so we can say public static because we want to be able to access it from anywhere and then we'll return an input manager and this will be called instance so this is called a accessor so we can do get and this will access our instance and we can just return our instance and then we actually have to fill this in because currently nothing is actually populating our instance and we can do that in our awake function so we can say if our instance does not equal null and our instance does not equal this that means that there's another instance in existence and we don't want two instances of this script so we can just destroy this.gameobject else we want to assign the instance to this script all right so now that we have a singleton ready now in our start we can say input manager equals input manager dot instance and there we go now we have our input manager stored and we want to store it so we don't have to call this instance each time we just need a reference to it once and down here under move let's just erase that we can do vector 2 movement equals input manager.getplayermovement so this returns our player movement and then we can do a vector3 move equals new vector 3 and so movement is in vector 3d so we have to convert our movement to a vector 3d so we can do movement x 0 and then movement dot y and we put zero in the y because that's jumping and we're gonna do that later on and down here we can also change our input get button down to input manager dot jumped this frame player jumped this frame and so yeah this is now adapted to use the new input system so let's set up our player in our editor so let's right click and create a new empty object and i'm going to rename it to player and then i'm going to be adding in a player controller and we also have to make sure to add in a character controller and so another great thing that you can do to actually make sure it as in a character controller is that you can say require component type of and then we can put character controller so this script will not run if it does not have a character controller and i'm going to erase these two using statements since we don't need them all right and so now we have our character controller and so currently the camera is not following our player so let's just add in a cube or something to make sure that we are moving in the scene and lastly very important i forgot to actually add the input manager so right click create a new game object and call it input manager and let's add in our input manager script because you still need to add in the script to have an instance of it all right so now we're moving around and you can see that now the cube is looking around and moving around and it changes rotation depending on where it's moving awesome all right so let's set up the cinemachine which is the main part of this video so first of all up here we have ace in a machine tab and so we actually want to create a virtual camera there's a bunch of different kind of cameras that are useful in different occasions but in this case we just want the general one and so a virtual camera does all the movement calculations for us and then in the main camera you see that it has added a cinemachine brain and it basically tells the brain how to move in the scene so we want to focus in on the virtual camera and we want to focus especially here where it says follow so we want the camera to follow our player so we actually have to drag in our player into that follow and so now you see the camera changed position and for a first person mode we actually want to change here it says body we want to select hard lock to target so this will actually lock itself to the target and move with the target which is exactly what we want and so i've and so i've actually replaced the box with a capsule so you can see it better alright so now we have our camera and we want our camera to be kind of more up on the capsule so you can see that our camera is in the center of our player if you'd like you can actually right click and create an empty under the player and you can move it up and then under our virtual camera we can actually replace our follow with our new game object that we just created so that it's centered more at the top of the player if you have an actual character with different body parts and bones this is easier but now that we have this done let's actually make this aim aim in the direction that we want it to so for our aim we want to select pov which is point of view so we want to be in the point of view of our character looking out and then you can see that it has an input access here mouse y and mouse x this is for the old input system we're going to be overriding these values so let's delete mouse x and mouse y and we actually have to override these but how do we do that well it's a little tricky and it's not fairly obvious how to do that since if you try to get the virtual camera itself there's no field to actually change the input axis name so a little work around is that we can make an extension for our cinemachine camera that overrides those values so let's right-click and make a new c-sharp script and let's call it cinemachine pov extension all right so first we want to delete these two using statements and we're going to say using cinemachine and now we actually have to derive from the cinemachine extension so we can use its methods and overwrite it and you can see that we have an error it does not implement the cinemachine post pipeline stage callback which is needed in order to inherit from this so i'm just going to copy that and so i made this into a function here and i'm going to call this protected override void and right here you see that it's the names of the objects themselves so let's call this one v cam cinemachine virtual camera base the stage we'll just call this stage camera state we'll call this state and our float this is actually going to be a delta time and this is one of the functions we're just overriding it that's all we're doing here all right so the way this works is that cinemachine operates in stages so you can see on the documentation we have several stages here our second stage for example is body which is position the camera our third stage is aiming which is orient the camera to point at the target and we're going to want to override the aim state so first we actually have to get a reference to our input manager so let's do a private input manager input manager and then in an awake function which we have to override since the thing we're inheriting from already has an awake function and then you can see here that it cannot be private it has to be protected a protected member can access things within its class and its derived class instances so if we put it protected then our parent can actually access these functions which of course we want and so here we can do input manager equals input manager dot instance and then we have to make sure to call base.awake which will call the awake function of our parent since we're overwriting this we want to make sure that we call the awake function because it might be doing calculations in there that we need all right so now in our post pipeline stage callback let's override the values so first of all we want if vcam dot follow so this is saying if we're following a target and then here we want to make sure we're in the right stage because this is called post pipeline stage callback is called after every stage post pipeline stage so we can do if stage equals so this will pass in the current stage and we can say cinemachinecore.stage.aim so if we're in the aiming stage then we want to aim so when you aim around you have to take into account your starting rotation because if not it'll be all sorts of funkiness so let's actually take into account our vector 3 starting rotation and then here we can just say if if starting rotation equals null then starting rotation equals and then we can do transform dot local rotation and then we can say euler angles so we're just getting the euler angles of our local rotation our starting rotation and now we want to get our input so vector 2 delta input equals input manager dot get mouse delta which is our helper function and so now we want to add in our delta into our existing rotation so we can say starting rotation dot x plus equals so we want to add in our delta input dot x and we're going to times that by time dot delta time same with starting rotation dot y plus equal delta input dot y times time dot delta time [Music] and so our starting rotation that y is our delta while we're moving up and down so ideally we want to clamp that value so that you just don't look up and then it rotates over your head because that'd be really weird so let's actually define some values here so let's do a serialized field and then we can do private float clamp angle so this is the angle we want to clamp at you can do a clamp angle for both directions but i'm just going to use the same one for the bottom of the player and the top of the player and i'm also going to go ahead and add in another serialized field and call it private float horizontal speed i'm just going to set it to 10 and same with the private float vertical speed so this is going to be the speed at which we look around so we can make it look around faster if we want all right so here we can say startingrotation.y we can say mathf.clamp which will clamp a value to make sure it doesn't go under or over our specified amount so we want to clamp our starting rotation dot y negative clamp angle and then clamp angle so you can think of the middle as zero and then if you look all the way down that's the negative clamp angle and if you look all the way up it's the clamp angle all right and now we can actually set our orientation so we can say state dot raw orientation equals and then we can do quaternion euler hope i said that right it's a tricky word for me and here's where it gets a little tricky so right away you'd go in and put starting rotation dot x for the x and starting rotation dot y for the y is what you'd think but unfortunately rotations don't work that way so for example if we were to go into our scene and i'm actually going to change the rotation of the y the y is the one that rotates it horizontally around the player because it's rotating around the y axis which is the green arrow and then if you rotate the x you can see that's what's rotating it up and down so it's as if you're looking up and you're looking down so that's what we're going to put in for our y so we're going to say starting rotation dot x for our y and then for our studying rotation dot y so we want the character to rotate up and down then that's the x so we'd actually put the starting rotation dot y into the x so i'm just going to explain that once more because i know it's confusing and i might have confused myself explaining it we move the mouse sideways we want to rotate it on the y alright so that's the basics and let's just add in the speed here so once again our horizontal speed is going to be added into the y so we can do times horizontal speed here and for our starting rotation dot x we can do times our vertical speed all right so now let's go into our virtual camera and let's add in our pov extension it's in a machine pov extension and let's click play and hope the best happens all right so unfortunately we're getting some no reference errors here and that's because i'm trying to get the instance in the awake function and the input manager assigns it in the awake function so we can quickly fix that by going to edit project settings and then under script execution order let's make sure our input manager so plus input manager runs before our sun machine pov extension so now let's find our cinemachine pov extension and make sure the input manager is higher on the list meaning that it will run first all right and so let's begin the game and now we can look around awesome so we look sideways and we can look up and down you can see though when we look down we actually look up and then when we look up we actually look down so it's currently inverted so let's actually go into our cinemachine pov extension and add in a negative in front of the starting rotation.y and i'm just going to put this in the input manager but you can actually do cursor.visible equals false so that you don't see the cursor while it's playing alright so now we can look up we can look down we can look sideways and if you don't have the cursor visible disabled you'll actually confuse yourself moving around currently our player moves in the opposite direction of our camera and that's because we didn't actually change our character controller script to account for our camera position so let's do that really quickly and that will be the end of the video after this so in our player controller we want to keep track of the camera transform so private transform camera transform and here we can do camera transform equals camera.main.transform so we're getting our main camera the transform value and down here in the movement we are actually going to say move equals and now we're going to take into account our camera direction where it's facing so we can do camera transform dot forward so this is the forward direction of the camera and we want to move in this direction so when we press w or up we want to move in that direction and currently that's assigned to the z value of our move because remember we put the movement dot y on the z axis and then we also want to take to into account moving sideways so camera transform dot right and then we have to times this by the move dot x all right and then the last thing is that we have to remove this if statement that actually changes the game object transform forward if we're not moving because if not it'll rotate the character for us and obviously we don't want that and another thing that we want to do is actually make the move dot y equal to zero because after we change the move value it might change the y and we want to make sure that the y is zero because we'll be performing the jump action later on in the script down here and so one bug i was facing previously was that sometimes it doesn't jump very often and that's because we have to set the min move distance to zero and that's the minimum distance that the character controller moves if the character tries to move less than the distance it will not move at all so if you put that to zero it will jump whenever you press jump and so i'm just going to remove the capsule here all right so now everything should work we look around when we look down nothing happens we can go backwards forwards everything works pretty well so yeah that's the basics of this video thanks so much for watching i hope you enjoyed if you have any questions feel free to drop them in the comments below or in my discord channel that's in the link i'd like to thank all my patrons for all the support thank you so much i really appreciate it and it goes a long way to helping me make these videos and if you haven't already the discord channel is in my description as i previously said and if you want to chat or just ask questions you can join so thanks so much and see you next time [Music] you
Info
Channel: samyam
Views: 82,208
Rating: undefined out of 5
Keywords: Standard FPS camera with Cinemachine, cinemachine first person, cinemachine fps, fps unity, cinemachine virtual camera, look around unity, pov camera, pov, pov unity, pov cinemachine, first person camera, cinemachine first person camera, first person mode cinemachine, first person character controller, first person movement, first person input system, new input system fps, input system first person controller, cinemachine first person camera unity, cinemachine input system
Id: 5n_hmqHdijM
Channel Id: undefined
Length: 24min 38sec (1478 seconds)
Published: Sat Oct 17 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.