Jumping! - 2D Platformer Player Controller - Part 22

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
what is up guys welcome to barton my name is heinrich and today we're going to add the ability to jump to our character last episode we set up the finite state machine and got started with our movement and idle states so to get our jump working we're going to take a look at our ability super state our jump sub we also need to take a look at our in air state and then lastly we'll look at our land state so to get started let's head over to unity and let's just go ahead and create the scripts for each of these states so we can come to our super states folder let's create a new c sharp script and let's call it player ability state after that we have three sub states our first one is going to be our jump state so player jump state next we have our in air state so create c-sharp script player in air state and then finally we have our player land state we can now go ahead and just open all those up and now that we have all three of these open let's just go ahead and turn them into actual states so let's start off with our player ability state we can go ahead and get rid of this code and then just make it inherit from player state seeing as this is our super state next we have our jump state which inherits from player ability state you can go ahead and get rid of that make this inherit from player ability state and before i actually forget let's go back to our player ability state and create the constructor and then do the same in our jump state so remember you can just right click quick actions in refactoring generate constructor or hit control full stop and of course that might be different depending on what editor you're using okay next we have our player in air state so in this case if we take a look at our state machine diagram you can see that our in-air state is not a child state for any other state so it's not a sub-state or a superstate currently there's just no other states that we really need to group this one with so this one can just be standalone same thing goes for our ledge climb which we're going to get into in a later episode so in this case we're just going to inherit from our player state so get rid of that and then inherit from player state and then just go ahead and generate the constructor and then finally we have our player land state and in this case player land state is a substate of our grounded state so just go ahead get rid of that and make it inherit from player grounded state and then generate the constructor okay so now all these classes are ready to be states the next thing we can do is actually set up the state objects in our player script so let's go ahead and open that up so we can come and open up our state variables we have three new states so our first one is going to be public player jump state and we'll just call it jump state and then we give it a public getter and a private setter next we have our player in air state so public player in air state and we'll just call it in air state and of course don't forget the public getter and the private setter and then finally we have our land state so public player land state call it land state okay perfect now that we have these states declared we can go ahead and initialize them or actually create the objects so that happens in our awake function which is a unitycallback function so here we have our idle state and our move state so next we have our jump state which equals a new player jump state we pass this as the player state machine as the state machine player data as the player data and then finally we need to pass it an animation boolean name now by our logic this should just be called jump but if you remember from the old controller we have a set of animations and a blend tree that we play if the character is not grounded and is moving up or down so the jump animation is actually part of the up animations so what we're going to do is in the jump state we'll be transitioning to the same animation state as our in air state so we can just call our animation boolean name that we want to set in air like that so next we actually have our in air state so an air state equals a new player in air state with this as the player again state machine has the state machine player data as the player data and then in air for our animation boolean name again and then finally we have our land state so land state equals a new player land state with this as the player state machine as the player player data as the data and then finally our animation boolean name is just going to be land with a lowercase l perfect and that's basically everything set up in the player so now we're free to transition to any of these states so let's first take a look at how we're actually going to register the jump so what we need to do is come to our player input handler and over here we have our onjump input function so what we're going to do is come up to our variables and create a public boolean and we'll just call it jump input with a capital j and then give it our public getter and our private setter and then all we need to do is come to our on jump input function and say if context dot started so this means our jump button has just been pushed down then we want to set jump input equal to true then if we take a look at our state machine diagram you can see that from our move state and our idle state and really all of these states if we push the jump input so we have an ability input we're going to come to our jump state that means this transition that's based off of our jump input should come from our grounded super state and not one of our sub states so let's go to our player grounded state and let's just create a private tool call it jump input and then in our logic update function we can go ahead and read that in like before so jump input equals player dot input handler dot jump input simple as that so whenever we push the jump button it's going to set this boolean to true and then we'll just read that in in our states so now in our logic update after this we can say if jump input is true then we can transition to our jump state so we just say state machine dot change state to player dot jump state just like that now there's a couple more things we need to do let's just go ahead and test this to see if we actually go to our jump state so when we run the game and we open up our console and then we push spacebar you can see we change to in air so yeah we successfully transitioned to our jump state but everything is broken now as we have not yet set up the inner workings of the jump state but we have another problem and that is once we set this jump input to true in our player input handler there's nothing that sets it false so normally what we would do is in our on jump input function over here we would directly call the function that causes the player to jump but seeing as we're using this whole state machine system to make it so that we can choose when we want to read in our jump input and when we don't we can't do that from here but at the same time we can't just set this to true and then set it back to false because then we might run into a situation where our state has not had a chance to read this input yet so what we're going to do is create a function that sets jump input to false whenever we use it so below our on jump input function let's just go ahead and create a public void and we'll just call it use jump input this function does not take any input parameters and it only has one purpose all we do in here is say jump input equals false now a little thing that i discovered recently if we have a function that only has one line of code there's something we can do to make it look a little bit prettier so it doesn't take up so much space so over here on the left you can see there is recommended quick actions and at the bottom here it says use expression body for methods if we go ahead and click on this you can see that the way of writing this in a single line is just saying the function name and then equals greater than then what that one line is so it's saying when you call this function just do this and this is actually quite a nice way to make your code look a little prettier but again you could leave it the other way it's really not an issue so now we're going to do is in our player grounded state before we transition to our player jump state let's just go ahead and call that function so we'll say player dot input handler dot use jump input so now basically the jump input gets set to true and then once we use it we set it back to false cool so we can now work on our jump state let's go ahead and take a look at that and our jump state is actually very simple all we do is just set our y velocity so before we can do anything here we first need to come to our player data and let's create a new header and this header is going to be for our jump state and the first variable that we want to declare is going to be our jump velocity so we have a public float jump velocity and by default let's just go ahead and set it equal to 15. and now that we have our jump velocity we still need to create a function to set our y velocity as we currently only have a set function for set velocity x so let's go ahead and create that quickly so we're going to create a public void set velocity y and this function is going to be exactly the same as our set velocity x so it takes in a float parameter called velocity and then inside the function we just say workspace dot set and we want to set it to current velocity dot x and on the y we set it to velocity then we just need to go ahead and apply that velocity so rb dot velocity equals workspace and then we update our current velocity so current velocity equals workspace just like that so now in our player jump state we can just go ahead and generate our overrides and for our jump state we really only need our enter function so let's just go ahead and generate that and now in our function we can just go ahead and say player dot set velocity y and we just want to set it to player data dot jump velocity so now we can go ahead and quickly test that we're still going to get stuck in the jump state but at least we can see the character jump boom just like that and again we're stuck so now we need to transition out of our jump state so the thing with our jump state is our transition is basically instantaneous once the jump is over we're going to transition to our in air state but our jump state is part of our ability super state so we're going to do is once we've applied the velocity we say okay this ability is done and then our ability super state can take over and determine where it needs to transition to now so let's go to our player ability state and let's just immediately come and generate our overrides we don't want the first three just like that and so the first thing we want to do is create a variable that is going to be protected and it's going to be a boolean and we'll just call it is ability done so this is the boolean that our player ability state is going to use to know if the current ability is done or not so then we just want to come to our enter function and by default we're going to set is ability done equal to false in our player jump state after we set the velocity we can then just go ahead and say isability done equals true cool so now in our playability state we just have to transition to the appropriate state so currently we're going to have two cases that we can transition to either when the ability is done we are grounded or we are not grounded in the case of being ground we'll just transition to our idle state and in the case that we're not grounded we're going to transition to our player in air state so what we need now is the ability to determine if we are grounded or not so to do that let's come back to unity and if we look at our old player we have a groundcheck game object so on our player let's just go ahead and create an empty game object and we'll just call it groundcheck and then the position for ground check we can just use the same again is zero on everything except for y which is negative 0.941 so that is currently at middle bottom of our player so on this position we're going to do an overlap circle to determine if it's detecting ground or not so this is where our next check function is going to come in so in our player class we can go ahead and minimize our set functions and open up our check functions so we're going to have a function here that's going to return whether or not we're touching ground so just write that above our check if should flip so we will have a public bool because this function is going to return true or false and we'll just call it check if touching ground like that and now in this function we're just going to say return physics 2d dot overlap circle and in this case we're going to use this version of the function so we require a point a radius and a layer mask so the point is going to be given by that game object that we just created and then our float radius and our layer mask are two other variables that we need to create so let's just quickly go ahead and make those the first thing we need is our vector 2 point so let's come up to our other variables and really we can make another region here for all of our check variables because we're gonna have a bunch of those little transforms that we're going to use so i should go ahead and say hashtag region and just call them check transforms and then we can go ahead and close the region so now inside of this we can create a serialized field private transform and we'll just call it groundcheck next we need the radius of our ground check so that we'll do in our player data let's just go ahead and create another header this time it's going to be called check variables and so under this we'll declare our public float ground check radius and then next we have our layer mask so this is public layer mask and we'll just call it what is ground now our ground check radius we can actually just set to 0.3 by default cool so now that we have that declared we can come back to player and then in our check if touching ground we can start off by passing it our groundcheck dot position next comes our playerdata.groundcheckradius and then finally comes our layer mask which is playerdata.what is ground so this function will return true if overlap circle detects ground so what we can do is in our player ability state let's go ahead and create a private bool called is grounded and so in this case i'm using private instead of protected because i don't think any of my abilities will need to know if they're grounded or not but again if you have an ability that does need to know this information you just set it to protected we can then come to our do checks function and just say is grounded equals player dot check if touching ground and i think a better name for this function so we can just click on it click control r twice is just check if grounded like that it fits the variable name better so now with this information we can determine where we want to transition to so let's come to our logic update function and we'll say if is ability done then if is grounded we want to transition to our idle state so state machine change state to player dot idle state and then if we are not grounded so else state machine dot change state to player dot in air state like that but there's actually something else we need to add here because seeing as our jump ability is instantly over we're still going to be detecting ground at the very beginning of our jump so we want to make sure this only applies if our velocity is less than or equal to zero so we can just go ahead and say and player dot current velocity is less than 0.01 f and this should be current velocity dot y so now let's go ahead and test that in unity the first thing we need to do is come to our player and drag in our ground check transform then if we run the game and we jump you can see over here we have two cases where it prints out in air so this is when it goes to our jump state and this is when it goes to the in air state perfect so this means we can now move on to our in air state so let's head to that script and let's go ahead and generate our overrides okay perfect so now let's think about what we want to have happen in our in air state if we look at our state machine diagram you can see that in our in air state if we get another ability input so if we push spacebar again and we have the ability to double jump we'll come back to our jump state otherwise we'll just stay in the in air state and if we detect ground we go to our land state other than that we have some transitions down to our different wall slide and ledge climb in those states but we won't worry about those just yet so currently the only thing we're going to worry about is our transition to our land state so in our player in air state let's go ahead and create another boolean so we have private bool is grounded again we can just go ahead and add that to our dude checks so is grounded equals player dot check if grounded so in our logic update function all we have to do is again say if is grounded and our player dot current velocity dot y is less than 0.01 f then transition to our land state so state machine dot change state to player dot land state just like that now another thing we want to do in our in air state is give ourselves the ability to actually move so in our grounded state we have a move state and an idle state but the main purpose of that is the fact that we have different animations in our in air state it's the same animation tree taking care of all the animations so also just read in our x input and move the player accordingly so let's go ahead and declare a variable for our x input so private int call it x input and i'm actually just going to move it above the bool then in our logic update the first thing we can do is read in that x input so x input equals player dot input handler dot normalized input x so now we only want to move the character if we're not actually transitioning to a different state so after this if we'll just have an else so we'll say player dot set velocity x and the velocity we want to set it to is our player data dot movement speed or movement velocity multiplied with our x input and so what's cool about this is if we wanted a different type of movement when we're in the air so maybe something that's not as responsive we could just use a different function here and before we actually set the velocity we also want to check if we should be flipping the player so player dot check if should flip and we just pass it our x input okay let's go ahead and test it so back in unity we just need to click on our player and come to our player data and just set what is ground equal to ground and then if we run the game and we run and we jump as you can see we have now transitioned to our land state when we detect ground so currently we don't have any of our animations set up yet so we're still getting these uh parameter issues but it's a start so now before we move on to our lan state let's actually go ahead and set up the animations so if we go to our sprites folder and look at player character one so there are actually two different jump animations this time there's one for when we're jumping without x input and there's one for when we're jumping with x input and then we just have the same fall animation and then our land animation so if we just take a look at our old player jump fall blend tree you can see we have animations jump one jump to jump three where jump three is our falling animation jump 2 is like the middle transition animation and then jump one is our rising animation so we're going to do something very similar to this except instead of being based off of one variable we're going to have two variables here we'll have our x velocity and our y velocity to determine which of the starting animations should be playing so let's go ahead and click on our player then let's right click say create state new from blendtree and let's just go ahead and call this the same thing so this is our jump full blend tree then if we go ahead and click on the blend tree itself we can set what our blend type is so currently it's set to 1d so only one parameter so we want to go ahead and set the blend type to 2d freeform directional and as you can see now it gives us the options of two different parameters it created this blend one for us so we can actually go ahead and rename that to y velocity and then let's create another one so these are floats this is going to be our x velocity and yeah so now we need to go ahead and create the animations so we're going to end up with quite a few animations so let's go ahead and drag up our animation window and head over to our game view and we can then click on our player and then create a new animation clip we just have to navigate back to our animation folder animations player and so let's call the first one jump up one and then let's create another animation this time it's going to be jump up one x so jump up one is going to refer to our first jump frame where we have no x input so in that case it's this one and then jump up one x is going to refer to this animation sprite so we have jump up one jump up two and then jump up three so we're going to have six different jump up animations let's just go ahead and finish declaring those so we have jump up two and then jump up to x then finally jump up three jump up 3x after that we have our full animation which is three different frames but in this case all three of these are just going to be part of one animation so next we just have a full animation like that so let's go ahead and drag in all of our frames let's start with our non-x animations so come to jump up one seeing as we only have one frame the sample rate can stay at 60 and in this case it's sprite number seven drag that in that's what that looks like next we have jump up two which is going to be sprite eight and then jump up three is sprite nine and now for jump up one x it's going to be sprite number four jump up two x is sprite number five and then jump up three x is going to be sprite number six after that we have our full animation and in this case we have three different frames so sprites 10 to 12. let's go ahead and drag those in there and seeing as we have three different frames we're going to want to change the sample rate i'm gonna make it five let's see what that looks like maybe a little bit too slow let's make it something like eight yeah that looks good as you can see it's literally just the same frame except the little hoodie is waving in the wind and then our final animation that we need is our land animation so that's going to be sprites 13 till 16 whereas sprite 16 is just our first idle animation sprite so create a new clip and we'll just call it land and then we can go ahead and drag in these sprites so sprite 13 to 16 throw that in there doing some mad squats change the sample rate to i guess eight as well let's see what that looks like perfect so seeing as we're looking at the lan animation let's just quickly talk about what that state is um this state is more so about game juice than actual mechanics so what happens is when we land on the ground if we're not giving x input we finish this land animation but if we do give x input we immediately go to our move state so it just adds a little bit of polish to our movement if i can if i can say it like that you'll see once we implement it okay so now that we have all these animations made we can go ahead and close the animation window and let's click on our player and then come back to our animator if we go back to our base layer you'll see all these animations that we just made in this case we can just go ahead and delete all of them except for our land animation which we can just drag up here let's go back into our jump fall blend tree and then let's click on our blend tree again and here we have our list of motions where motion is the animations that we want to use so let's just click the plus sign and say add new motion field but as you can see we currently only still have one slider that we can change that's because our parameters is currently set to both of them on y velocity so let's go ahead and change the second one to x velocity i think that's the right one and yeah now let's go ahead and add all of our motions so we have six jump animations and one fall animation so that's seven total so one two three four five six seven let's just go to our project window and let's go to our animations folder player let's go ahead and drag in all of these animations so we'll start off with jump one then we have jump two then jump three then let's do jump up x jump up two x and then jump up three 3x then finally let's put in our fall animation boom okay so as you can see here if we adjust the y and x velocity sliders it's actually the opposite way around so the first one should be x velocity and then the second one should be y velocity so now if we change x that red dot moves along the x axis and if we change y it moves along the y axis so seeing as we have our jump velocity set to 15 we want to make our position y for our jump up one something close to that but below it so if our jump velocity is 15 we'll make this say 13. we want to do the same thing for jump up one x and then jump up two we'll do somewhere between that and zero so let's just do eight and then finally jump up three we can just leave on zero next we need to look at the x axis so jump up one two and three all of the x positions should be zero and then jump up one x two x and three x should all be one and the reason we don't also have to specify this for a negative x velocity is because we'll just pass the absolute value of the x velocity to this next we have our full animation so now that i think about it we actually have to add another motion field that is just going to be our full animation again but we just need this here so that we have one for a zero x velocity and then our y position is going to be let's just say negative three and then we need one for when we have an x input and negative three for the y position again so now if you play around with these sliders you can see how our how we transition between the different animations it's pretty cool okay with that set up we're just going to set up the transition to the blend tree itself so let's come back to base layer here we have our jump fall blend tree so we should just come up to our parameters create another boolean this time we'll call it in air drag that up to the top then we can make a transition from entry to our jump full blend tree set the condition to in air equals true and then we make a transition from our jump full blend tree to exit and this time we untick has exit time the transition duration is zero and our condition is that in air is false now before this will work we actually need to set our y and x velocity parameters so let's come back to our in air state and then in our logic update in our else function let's go ahead and pass in the values to those parameters so after we set the velocity let's just go ahead and say player dot anim dot set float and the first float we want to set is going to be our y velocity and we just want to set this to player dot current velocity dot y next we want to set our x velocity so let's just go ahead and copy and paste this change this to x velocity and now instead of setting it to player.currentvelocity.y we want to do dot x but we also want to come and say math f dot abs so if we have a negative x velocity the animation will still work correctly math f perfect and i think everything should work now so let's give it a little try as you can see our jump animation works and as you can see we're in the land state so we can't move or anything because we don't have any like local transitions out of land state but because land state inherits from grounded state we can still jump so really we can't test the uh x jump let's give that a try as you can see it plays the x-jump animation which is really cool it adds so much um i'm really proud of that okay so now let's take a look at our land state our land state script is very simple as well so player land state and this time all we need is our logic update function so let's go ahead and generate overrides deselect all select our logic update and all we need to do here is if we have x input we transition to our move animation or our move state and if we don't have x input we just let the land animation play and if the lan animation is done we transition to our idle state so we'll just go ahead and say if x input which we can do because we're already reading in the x input in our player grounded state does not equal zero then state machine dot change state to player dot move state and now after this we're going to have an else if and this is going to check to see if our animation is finished so we actually have to add something else to our player's state script so let's go ahead and open that back up we can get it from scripts player player finite state machine player state so in our player's state script we're going to create two more functions that we can call from our animations and you'll see how we do that so the first one is just going to be a public virtual void and we'll call this one animation trigger like that so this function isn't going to hold any code inside of it so we'll just leave it like this we can actually do the same with these functions just to make them look a little prettier that's too much effort i'm not going to do that now we can take care of that later but anyway so we have this animation trigger function and seeing as we put it in player state that means every single one of our other states will have this function and our next function is going to be public virtual void and this one will be animation finish trigger now our animation finish trigger is actually going to do something if we come up to the top we can declare a protected bool so we can just call is animation finished by default we can come to our enter function and set that to false so is animation finished equals true and then in this animation finished trigger we can just make that set that to true so put the little arrow like that and just say is animation finished equals true and if we do the shorthand we should get rid of the squiggly brackets just like that perfect so now every state has this animation finished trigger function that we can call to let the state know hey the animation that you're playing is actually finished and this comes in really handy the animation trigger we're not going to use right now but we just use it if we want to trigger something in the middle of an animation and we will make use of this later you'll see so now how do we actually call these functions from our animations to do that we need to come to our player script and we're going to create those exact same two functions that just call those functions on our current state so let's open up our other functions and above our flip function let's create a private void animation trigger function and this function is simply going to call state machine dot current state dot animation trigger so basically interacting with these functions the same way we do with our logic update and physics update function so seeing as the player script sits on the actual game object we can call this animation trigger function from our animations so after this we just have private void animation finish trigger and again equals greater than state machine dot current state dot animation finish trigger like that so now in our player land state what we can do is say if is animation finished then state machine dot change state to player dot idle state and now before this is going to work we have to come back to unity come to our animation window click on our player come to our land animation and at the end of the animation so over here we just need to add an animation event and then the function we're going to call is you might need to scroll down to find it is our animation finish trigger like that so now we just have to come to our animator and actually set up the transitions over here so we can create another boolean parameter this is our land boolean move that up to the top let me just make a transition from entry to land click on it set the condition to land is true then make a transition from land to exit click on that untick has exit time the transition duration is zero and then the condition is land must be false so let's give that a try so if we jump okay it doesn't appear to be playing our land animation let's see what's happening there okay the land animation finishes really quickly let's double check our code real quick okay so i found my mistake and it's really quite dumb back in the code in our player state script um in the enter function i set is animation finished equal to true by default we're actually supposed to set this equal to false by default okay now it should work as we want it to so as you can see when we land we slowly stand back up but if we're running and we land he just keeps running okay so also our camera is not currently following our player that's because our player camera is currently following our old player so let's just go ahead and drag in our new player this should make it look a little bit better there we go there's our land animation and there we just ignore it perfect okay so now we currently still have an issue a couple of issues as you can see if i'm if i jump and i spam spacebar he immediately jumps again once he lands so that is because we have this code here in our player input handler jump input gets set to true and only gets set to false once we actually use this jump input so that means if we press the jump button in a context where we can't currently jump it's going to hold on to that jump input until we can jump and then it'll use that jump input so we don't actually want this but we kind of do if you remember in the old series we had a thing where we saved the input for you know like 0.2 seconds just in case we push the jump input a little bit too early that way it doesn't feel like our jump input wasn't registered we can still use that so we're essentially doing the same thing here we're just never setting jump input back to false so now another thing that we're going to add to our input handler is a timer for our jump input so what we're going to do is come up to our variables and we're going to declare a serialized field private float and let's call it input hold time so this is how long are we going to keep the input true before we set it to false by default i'm just going to set it equal to 0.2 f and then next we need to declare a private float and this we're going to call jump input start time so when did we push the jump input we'll then come to our on jump input function and after we set it to true we'll say jump input start time equals time dot time next we need to create our update function so seeing as our input handler is still a mono behavior we'll have an update function and now in this update function we're just going to check our input start time versus the current time and then set our jump input to false if hold time has passed so let's actually create another function underneath our use jump input function and we'll just call this private void check jump input hold time and then in this function we'll just say if time dot time is greater than or equal to jump input start time plus input hold time if this is the case then we want to set jump input equal to false so this now means when we push the jump button our input will be held at true either until we use it or until time runs out so now before we forget we just need to make sure we come and call this function in our update function so if we run the game again and we jump as you can see if we push the spacebar while we're falling nothing happens but if we push it right before we land so we haven't technically landed yet it'll still register it as a jump because it holds it for 0.2 seconds awesome i'm noticing a little bit of an animation glitch there i think it's from my land animation we actually don't need this last frame because that's just the first frame from our idle animation this one so just go ahead and delete that and then move our trigger one frame forward perfect okay so we have some pretty decent jump code going now now what if we wanted to add a double jump so this is where our number of jumps is going to come in like we had before in the old code so how we're going to do this is let's start off by coming to our player data and in our jump state let's declare a public int and we'll call it amount of jumps and by default we'll just set it to one then in our player jump state so we'll come up and declare a private end that we'll call amount of jumps left so this integer is going to store how many jumps we have left it'll usually be one when we jump it gets set to zero if our player data amount of jumps is set to two you know then we'll have the ability to double jump so in our player jump state in our constructor let's actually set this by default to our amount of jumps so we'll say amount of jumps left equals player data dot amount of jumps now we need to create two new functions in our jump state class one is going to be to check if we can jump based on our amount of jumps left and the second one is going to be used to reset the amount of jumps that we have left so we have a double jump and we want to reset once we land so let's create two new public functions the first one is going to return a bool and we'll just call this can jump and inside this function we'll just say if amount of jumps left is greater than zero then return true else return false next we need a function for resetting the amount of jumps left so this is going to be a public void and we'll just call it reset amount of jumps left and all this function does is say amount of jumps left equals player data dot amount of jumps and actually another function we need is a function that decreases the amount of jumps that we have left so we'll say public void decrease amount of jumps left like that and all this function does is say amount of jumps left minus minus and you'll see why we need this function in just a second so now what we can do is come to our player grounded state and here we have a if jump input and then we can also say and player dot jump state dot can jump so basically if the amount of jumps left is greater than zero then go to the jump state we also want to come back to our player jump state before i forget and then in the enter function decrease the amount of jumps left so amount of jumps left minus minus like that and now that we have the ability to double jump we should also check our jump input in our player in air state so let's come up to our variables declare another bool call it jump input then in our logic update we'll say jump input equals player dot input handler dot jump input like that so now currently we only have a transition to our lan state so we'll add an else if and the condition in this case is jump input and player dot jump state dot can jump then state machine dot change state to player dot jump state just like that perfect and now one last thing that we need to do is reset the amount of jumps left whenever we go into our grounded state so we can just come to player grounded state and in the enter function we'll say player dot jump state dot reset amount of jumps left so now if we go back to unity and we click on our player go to player data and set the amount of jumps that we have to two we can then run the game and as you can see we can now jump twice but we can only jump after we touch the ground again perfect now we're basically almost done with this episode we just have one more issue left and that is look what happens if we just run off of an edge you can see we stay in our idle state that is because we currently don't have any of our transitions set up from our grounded state to our in air state so as you can see it's it's a very simple transition it's just if ground is not detected transition to in air so in our player grounded state let's create another private boolean and we'll call it is grounded and then in do checks all we say is is grounded equals player dot check if grounded and then in our logic update function here we have our transition to our jump state so after this we just say else if not is grounded then we want to transition to in air state so state machine dot change state to our player dot in air state and this is where our decrease the amount of jumps left function comes in because when we run off the edge we don't want to be able to jump anymore if we haven't jumped yet so if we have a double jump we want to have one jump left if we only have a single jump after we run off the edge without jumping we can no longer jump so in the player grounded state before we transition to the in air state we will say player dot jump state dot decrease the amount of jumps left so if we go back to unity and let's just set the amount of jumps to one if we run off the edge as you can see we can no longer jump although we're currently getting stuck on the wall i don't know why that is i think why is this happening okay so that is happening because we don't have our zero friction material on our rigid body 2d or our box collider so we can just come to project materials player matte as you can see it's just a simple material with zero friction zero bounciness and we can just drag that onto the material slot for our rigid body 2d that should fix it yep perfect we have one jump and we can run off the edge and everything works the way we expect it to awesome now one last thing that we can take a look at is coyote time so coyote time is basically when we run off an edge for a split second we still want to give the player the ability to jump so just in case he pushes the spacebar just a little bit too late when he meant to jump from the edge so this is also quite simple to implement so what we'll do is come to our player in air state and we'll just declare another bull and we'll just call it coyote time and basically what we're going to say is if coyote time is true and we push spacebar we want to jump so currently over here we have else if jump input and player.jumpstate.can jump equals true then we go to the jump state but what happens is when we run off the edge our player grounded state decreases the amount of jumps that we have left so in our in air state this can jump will return false if we only have one jump so now instead of decreasing it here in our grounded state what we'll do is when we transition to our in air state from our grounded state we'll start the coyote time and then only once the coyote time finishes will we decrease the amount of jumps that we have left so that will give us a split second after we've run off the edge that we can still jump so currently we have this coyote time bool all we need to do now is create a function to start the coyote time and then a function to check the coyote time so after our physics update let's create a private void check coyote time and inside this function we'll just say if coyote time is true and time dot time is greater than our start time so remember start time is a variable that we have in player state that saves the time every time we enter the state plus and now we need to know what our coyote time is so we can actually just come to our player data and we'll just create another variable for our in air state variables so header in air state like that and the variable we want is a public float coyote time and by default let's just set that equal to 0.2 as well 0.2 is a really good number then back in our player in air state we just want to use that here so if time.time is greater than start time plus playerdata.coyote time if this is true we want to set coyote time equal to false and then we want to decrease the amount of jumps that we have left so player dot jump state dot decrease amount of jumps left next we just need a function to start the coyote time so we'll say public void this time start kaioti time and all this function does is set coyote time equal to true so coyote time equals true like that and now before we go and call this function we just need to remember to call check coyote time in our logic update function so before we read the input we'll say check coyote time like that and then we can come to our player grounded state and now instead of decreasing the amount of jumps left over here we'll just come and say player dot in air state dot start coyote time like that now if we go back to unity we can actually just test this by setting it to a really big number so over here our time is zero for some reason um i don't know let's just set it to one so one second after we run off an edge we should still be able to jump that might have been a little bit too quick but it's i mean it's still yeah it's quite noticeable so if we just set it to 0.2 like we wanted and we try it up as you can see it still works but if we wait a little bit too long we can no longer jump and there we go very simple coyote time easy peasy okay now the last thing we have to do to catch up with where we had to jump in our old player controller is our variable jump height and we'll use the exact same method we'll detect when we let go of spacebar and when we do if we're currently jumping we just apply a multiplier that decreases our jump velocity so the first thing we need to do is come back to our player input handler and then we can create another public pool called jump input stop give it a getter and a private setter and this time we come down to our on jump input function and we'll say if context dot cancelled then we set jump input stop equal to true we also want to come up to our context that started and set this to false so jump input stop equals false simple like that we can then come to our player data and in our in air state section let's declare another public float and this time we'll have our variable jump height multiplier and by default let's just set it equal to 0.5 why not now in our player in air state the first thing we need to do is know whether or not we're currently busy jumping and then if we are jumping and jump input stop equals true we want to apply the jump multiplier so let's come up to our variables and let's declare another private bool called is jumping without the brackets it's not a function it's a variable and then we also need to read in our jump input stop boolean so let's go ahead and declare a variable for that so jump input stop then in our logic update function let's read in that input so jump input stop equals player dot input handler dot jump input stop now once we know this we'll just say if is jumping so if that is true then if jump input stop so we have that input we want to decrease our y velocity so we can just reuse our player dot set velocity y function and this time we'll just set it to player dot current velocity dot y multiplied with our player data dot variable jump height multiplier like that and the reason we have this the ifs nested like this is because we want to say else so if jump input stop is not true we want to check if we're still currently jumping or not and the way we check that is actually by having an else if and not just an else and then inside the if we say player dot current velocity dot y is less than or equal to zero so if we were jumping but our y velocity is now negative that means we're no longer jumping and we're just falling so don't decrease our y velocity if we let go of the space bar so inside this function we'll just say is jumping equals false and if we wanted to we could uh extract all of this code into a separate function just to make it a little bit cleaner so let's actually do that we'll just create a private void check jump multiplier why not and let's just take this whole if statement cut it from here put it in here and then let's call this function up here perfect so now the last thing we need to do is actually set is jumping equal to true to begin with to do that we'll have another public void function like our start coyote time function down here so public void and we'll just call it set is jumping and again this function only does one thing so we'll say is jumping equals true then we want to come to our player jump state and after we set our velocity we'll say player dot in air state dot set is jumping so this is only going to get set once we jump if we save this and give it a try you can see if we hold space bar we jump all the way and if we let go quickly we have a very short jump but we seem to have a little bug let's take a look at our code and i think it has to do with our check jump multiplier so okay so we also need to set is jumping equal to false after we decrease the y velocity so is jumping equals false that way this only happens once as you can see if we just tap spacebar we get a very tiny jump if we hold it we get our normal full jump and so yeah that's a very simple way for us to implement a variable jump height and i think that's going to do it for today so just a little recap we now currently have the ability to jump we have an in-air state that allows us to move in the air and then once we hit the ground we land or we just keep moving so really on our way to getting our character back to where he was before in the next episode we're probably gonna start working on the wall jump which is not something that we currently have but yeah we have a pretty good start to our character again now we can move we can jump all the basics so that's gonna do it for now before i go i would just like to thank all of my supporters and wonderful people on patreon and a huge special thank you to triac cody lee pyroses and miguel gray for your support on patreon you guys are awesome and i hope you guys all have a wonderful day
Info
Channel: Bardent
Views: 10,883
Rating: undefined out of 5
Keywords: Unity., tutorial, player, 2D, platformer, walljumping, wall sliding, jumping, Unity, Animation, ground, check, physics2d, castcirlce, variable, jump, height, Wall, Jumping, Movement, improvement, user, friendly, code, 2019, 2019.2.0f1, Ledge, climb, dead, cells, system, easy, beginner, animation, Dash, Ghosting, After, Image, After Image, Unity combat, Comabt, Melee, Melee Combat, Basic, Enemy, Patrol, State, Machine, respawn, hit, finite state maching, state machine, enemy, behavior, Archer, FSM, New, Input
Id: dOiOp3DLxZQ
Channel Id: undefined
Length: 62min 22sec (3742 seconds)
Published: Sat Aug 01 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.