Godot One Shot : Platformer with Rolling and State Machine

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
welcome back to another look rs tutorial this time we're going to do a platformer and it's just going to be the platform controller in this case um mainly because quite a few of my students have looked at different platform tutorials and there are loads of them out there for good old lots of them really good but a lot of them don't cover some of the things that they're wanting it to do now this one is going to be quite simple and then i'm going to do another platform tutorial which is a bit more complex which is going to have utilized some of these other animations in here which is the hanging and the multiple attacks as well so this one here we're just going to get a basic attack in we're going to get it running i am going to have it jumping and also sliding in this case which you could substitute for a roll as well so there is a roll and a slide animation in this one this is a really popular one it's on each dot io just look up um animated pixel adventurer it is it is free you can throw the guy a few dollars if you decide you actually want to use this in something but i'm just going to use it for demonstration purposes today so i've got my goto project here i'm going to bring that sprite sheet in i've got it open over here so let's bring it into here and just because this is a new project i will set it to 2d pixel and import that all right so my scene i'm going to build this all up in just one scene just to demonstrate things so i'm just going to call this world and we're going to get a test platform here so i'm going to make a static body and this static body is going to have a collision shape and it's also going to have a sprite now because i'm not too worried about what it looks like i'm just going to put the texture there and i'll pop that down here oops no i won't i'll pop it up here and we'll set the collision shape to be a cube rectangle and we'll make it fairly long there we go like that and i'm not actually going to have a sprite i'm just going to delete that the reason for that is i will go visible collision shapes now i'm going to click this static body 2d and turn on that little bit there so i'll move that over to here all right so there we've got our platform we could have multiple platforms here so that we can demonstrate the roll and the jump and i'll put one more in there we go all right next thing is to create the character so we're going to have a kinematic body for the character kinematic body it's going to have a collision shape and it's going to have a sprite and it's also going to have an animation player in future in the next one i will look at using an animation tree animation player there we go collision shape all right let's go ahead and with this sprite bring the sprite in over here and now we don't want it like that this looks like it's one two three four five six seven and a bit sprites going across so let's just check this out it's kind of annoying that it's done that because it looks wider over this side so i'm going to say that it's eight across so animation h frames eight and it looks like one two three four five six seven eight nine ten eleven twelve 14 15 16 down okay so if i zoom in on that it should be all good and we can just check the frames oh no it's going across that way let's turn it down to seven and c no it goes that way well that's useless that okay in this case what i'm going to do is go to a website called pascal and i'm going to edit this sprite and i'm doing this because i know that someone is going to have this same problem as me so i'm going to import this maybe i can just drag it in yep import as a sprite sheet the frame size let's see i'm just going to check because i'm pretty sure i've got all the sprites here and the individual sprites should all be the same size they are so let's have a look and see what size these are this one is 50 by 37 so let's see if if i import these if it works 50 by 37 well that actually did work so i should be able to do that in there so one two three four five six seven no actually it this this is good here let's cut that right hand side up i'm going to import that replace it all good yep that's all good and then i will export it as a png and download this as a png nine columns 13 rows it's slightly different to what it was before but i will um now bring that back into my godot project so if i bring this back in here and i'll need to change these settings here so it was 9 and 13. okay now i can go through and test all those frames and they're all centered and in the right place so that's looking good okay with that done we want to get the collision shape sorted so i'm going to go ahead and add in the capsule i'll make that roughly the size of the character oops and make it a little bit thinner and a little bit taller that's pretty good there okay so with that done i'm going to go ahead and add in the animations so the first animation i'm going to add is going to be idle now i'm not going to do all of the animations i'm only going to do the ones that i need the idle animation is going to be only a few frames long i'm going to zoom in down here because i don't need it's definitely not going to be longer than one second so let's just go ahead and get it to about 0.1 for each chunk there and i'll click on the sprite and the first frame for idle is going to be this one and it's kind of annoying that when it does this it still stays at the first bit instead of going to the second so i'll go to the second one and then keyframe this and then keyframe it again and then keyframe it again all right so here's my idle animation if i change that down to 0.4 and then hit play there's my idle animation it's a there's one frame in there that maybe shouldn't be there which one is it i've done the first one twice which was dumb so i'll just delete that one and move those back and change it to 0.3 there we go that'll do i feel like i missed a frame there anyway new i'm going to use running okay so let's go ahead go to the sprite find the first running animation that's crouching that looks like the first running one we'll keyframe that and then go to here i'll just go back and make sure i'm on the first one yeah keyframe there and then i'll just keep keyframing it until we're done alright so there's that and it's 0.6 long so i can test that hit play that looks good i'm going to do a rolling animation and this one i'm going to find the role animation or i could find the slide animation i'll use slide for this one because it looks like that rolling animation is actually a jumping animation so let's go ahead and keyframe this i'll just rewind it back to there and two one okay so that should do that i don't want this one to loop um i just want it to kind of play once and that's it we could space it out a little bit longer but this is going to be a pretty simple roll it's just going to move a certain distance and that's it i could also keyframe the collision there as well because that is quite large when he's on the ground sliding i probably want to change the size of the sprite but i'm not going to because i'm just looking at getting the animations done here so i've got running let me just think what else i need i think i need a jump and a fall so new jump and i'm going to find the jump animation that's a hanging animation okay so this one here is the jump animation it's not going to loop i am just going to keyframe this here frame the first one and then the second one there now let's see what this does for oops reason those are the exact same sprites let's go ahead and keyframe that than that what i wanted to do is not really go between those two i'm just going to have one frame for this different sprite sets different things so i just really want to have one frame for it for now i could spend more time actually fixing it up and doing the jump the loop bit i'm not going to and then fall is going to be my next animation and that is going to be also 0.1 long and i'm going to find the sprite for that should be after that it's going to be that one and i'll keyframe that and create it all right so i've got all these keyframes done uh and the animations are in the animation player they're all there and there will also be an attack one may as well make that now actually attack let's find a the first attack sprite that's like a whole triple attack that's a better idle animation there but i'm just going to keyframe here let's go back one and keyframe keyframe i may as well just do that there we go he's got a double attack so that's going to be one second long that's not going to loop uh it will look like that all right i could make it a little bit longer 1.2 and maybe keyframe the next one out okay and then we don't want that last one there all right so i've got my animations here i'm going to go ahead and add a script to this i'm going to call a player controller or something similar to that and we'll delete this except for we'll just delete all except for the bit at the top all right now i just need to bring up my other project over here there are a few things we want to do right at the top here so the first one is going to be export in var speed equals 120. i actually don't remember if i even use these because i wrote the code um a few days ago jump speed i'm pretty sure i do equals negative 180 and then x4 gravity equals 400. now i've just got var velocity equals vector 2 now i did base some of this code on heartbeast's one bit pixel platformer but it's so far from what that was um that it's it's not really there's just a few lines of code in here now that are similar to his if you notice so i'm going to export float um i don't think i actually use friction or acceleration i don't know i do i do i do i think this bit here is from his pixel platformer just this movement code friction equals 0.1 export float 0 1.0 acceleration equals 0.25 and then i'm going to create an enumerator now an enumerator is i'll just build it up and kind of explain it as i go so it starts with enum then the name i'm going to call it state and then inside this here and the numerator is kind of like a dictionary um except this word running it actually has the value of zero this word walking has the value of one this word has a value of two uh rolling has the value of three jump has a value of four and 4 has the value of 5 except we don't want walking so i'll delete that now what this means is that i can create a variable and it's of type state and assign it these values it's just easier than doing it in a string so saying um player state equals string running because the code will give me an error if i don't use one of these enumerators and um it's easier than remembering a number as well so the next line is going to be player state equals state dot idle this is just saying well equals 1 in this case but i might just swap those around not that it makes any difference whatsoever so state.idle is the beginning state now we're going to write a little function here this function is straight out of half east one i think i might change it as i go here var direction equals zero if input i'm going to write this different and you'll recognize this from his stuff as well um equals import dot get action strength ui right minus input dot get action strength ui left so there's our input if direction is not equal to zero i'll just show you the original code the original code was where is it this here so we've just reduced those five lines down to one line which is going to give us this here so to understand this the action strength is going to be either zero or one um if you're pushing the key it's one if you're not pushing the key at zero if you're using like an analog controller you can actually get kind of um analog or like a fraction percentage 0.1.2 depending on how far along you're actually pushing it since we're using keys it's either on or off so it's going to be 0 or 1 take away 0 1. so the answer is going to be either 1 0 or negative 1 that will give us our direction and so if the let me just bring this back over i can continue with that code there we go i'll bring it over here so if the direction is not equal to 0 then velocity.x equals lerp velocity.x direction times speed acceleration so what this is going to do is it's going to take the existing velocity and it's going to calculate a number that is between the existing velocity um and the direction okay so if the direction is one we're going to calculate a velocity in between that we're going to kind of accelerate and then else velocity dot x equals lerp in this case we're going to move it towards zero velocity.x we're gonna move it towards zero friction okay so that's going to slow it down by the friction amount that's going to speed it up towards our direction so 1 or negative 1 times 120 by the acceleration amount in this case it's 0.25 but it will do that very quickly so it's going to do that every single frame okay so now what we need is the physics process func underscore physics process and we need delta in there i know this video is going to be quite a bit longer than my usual ones i may end up stopping it after we get this physics process done and we'll look at adding the animation stuff in part two but this is going to be very simple if player state is not equal state dot rolling and player state is not equal to state dot attack then we're going to get the input now there's a reason why i've done it this way and what's the error note okay so we do not want the player to be able to interrupt the attack or interrupt the rolling so if the game is in either if the player is in either of these states we're not going to do this code we're not going to get the input and we're also not going to assign it movement and other stuff here so if and now this bit's a little bit tricky and it's to do with how the movement code here works but i'll print some stuff out so you can see what's actually happening here what we'll do here is i'm just going to go if velocity dot x equals 0 because this will make sense so if velocity.x is equal to 0 then we are going to say player state equals state.idle okay so hopefully that makes sense if the velocity.x is equal to 0 player state is equal to state.idle when we run the game this won't work but i'll show you why i'm going to actually print velocity right here you can do this as well if you want so you can see how this works l if velocity dot x is not equal to zero and input dot is action just pressed ui roll or i'm just going to be down in this case then we're going to say player state equals state dot rolling now lf velocity.x so what i'm just going through is kind of the the sequence of of events that might happen in the game and the state that will respond to them so l if it's not equal to zero um then we're going to say player state equals uh wave is not equal to zero player state equals state dot run now you might think well won't it just set this to running no it won't because we've got elifs here so if this is true for a frame then it will set this and then in the next frame or the next time it updates in the physics process player state will be set to rolling and it won't do this and we won't change it back to idle or running until the roll animation finishes which we'll do shortly so then we've got another thing here we want to see if they're falling or rolling or jumping so lf this is just going to be an override here so we're going to be able to override the running or anything else by saying but if they're by pushing the jump key is on floor if is on floor end player state not equal the state dot rolling if they start rolling rolling takes over they can't interrupt that expected an in all right if input dot is action um just pressed ui i'm going to use up for jump that's kind of i don't like that for jump but it's easy now saves me rebinding keys velocity dot y equals jump speed so we're going to change that velocity.y to the jump speed and player state equals state dot jump and then we can add an attack here but i'm just going to comment it out for now add attack oops so we'll that's where we'll put the attack options there and then lastly we're going to tap back out so it's in line with this one and we're going to have an if not is on floor so if there is something that's going to override all of this and if the player is not on the floor then we're going to check whether they're falling or jumping and this is what the code is going to look like for that i'm just going to paste it in here oops if velocity.y is less than zero player state equals state dot jump did i put it as a jump yep um else player state equals state dot four so we've got this little state machine working here we're updating the different states that the game can be in and we're kind of locking off and blocking other actions now the final thing is to get the movement done then i may as well just do the animation now even though this video is going to be quite long i'm just going to double check that my audio is recording good and we'll this video will be quite long but that's okay velocity dot y plus equals gravity multiplied by delta so this is going to add the gravity to the sink velocity equals move and slide velocity and then we need to tell it which direction is up so we can check whether it's actually on the floor now i've seen a lot of tutorials a lot of things online say that you should not use move and slide until after is on floor because it updates the frame it really doesn't matter because it's going to update it here and then you can use it in the next frame anyway or the next update cycle i'm not sure what the technical term is there but i just call it frame so it'll update here and then when it gets back to the top it doesn't reset it it just changes the the flag if it is on floor so it should be it should be working let's hope that i don't get the glitch that i got um while while testing this and then lastly i'm going to print actually i don't need to print the state so this should all be working except for rolling rolling's not going to do anything now if i run this i'm going to it's going to probably give me a hundred errors let's just test this scene i should be able to um what physics process what have i done there oh i didn't put attack up here okay there's my character oh he went over there somewhere we'll just bring him back into the the world 2d he's slid off the edge okay i'll lock that there and move him over here okay so i can run i can jump up jumps down would roll actually down did roll then but there's no way to get out of the roll animation currently so the rolling is work the rolling state is working but we've got no animation to play so let's go ahead and go ahead and add in a function that will update our animation and we're going to do this right at the bottom after everything else so we're going to update animation i'm going to write a function up here func update animation now i'm going to take the code that i've already written for this and put this in and then you can just kind of pause it so the code looks like this i may need to check these things to see that my animation plays that same if velocity.x is less than zero we're going to flip the sprite horizontally but if it's greater than zero we are not going to flip this right horizontally we'll set it back to normal right facing then we're going to match the player state if the state is the idle we're going to play the idle if the state is not running we're going to play the running if the state is not rolling we're going to play rolling state dot jump etc state dot 4 etc with these though what we need to do is change at some stage change this rolling animation back to player state playerstate.idle and i'm going to test it in here but first of all we should see that this works i'm just going to check my animation names so we've got idle running rolling jump i'm just going to change that to jump and fall so let's test these okay it's the idle one's not working but the jumps working so up and down roll did work but it just keeps rolling so it looks like it's mostly working except for the idle animation so let's see why idle would not be working that's right i was going to explain why idle wasn't going to be working so you'll notice down here print velocity so let's go ahead and just move a little bit and you'll see this down here i printed out the velocity of the player i'm going to change this collision shape to a rectangle and just see if it does any better it's probably not got that quite right all right so we've got the velocity there uh that's working a bit better the capsule bit iffy with the 2d stuff um so if i move right you'll see that this velocity is going way down but it's still not actually equal to zero even though it's printing out here it's like a a fraction of one and it will just keep on kind of approaching because of that lerp it will keep on approaching the zero vector but never actually reach it now this may be an issue and there may be a way to fix that by using move toward instead of instead of lerp and i'll have a look at that in a sec but this is this was my little fix for it here if negative 30 is less than or equal to velocity is less than or equal to less than or equal to 30 then i just said velocity dot x equals zero so anything less than 30 or uh yep anything greater than negative 30 and less than that i don't actually know this code works in godot so let's just test it no it doesn't so i have to do it like this end velocity dot x is less than or equal to 30. um so you'll see here that if i i use 20 i think yep there we go anything less and he doesn't accelerate fast enough to kind of get past that initial movement but you'll see that it's now it slows down and at a certain point it does go to zero and sets it back to the idle animation right so that's working now we just need to make it so that he can stop sliding once he goes off the edge it updates that but we just make it so he stops sliding and this is where a handy little piece of code named yield comes in so we are going to yield and what we're going to do is say don't update or don't continue this bit of code here just remember it for a sec until we receive a signal back from the animation player that the animation player has finished and then we're going to say state dot player under source state equals state dot idle we'll just change it back to that because then in the next frame it's going to update this anyway so this here is how it should work so i should be able to slide and then it continues so i get that little slide animation happening the slide animation goes a little bit too long and it may be that the slide animation rolling is what i called it oh yeah see it goes out to one second so if i bump that down to 0.5 i could also have like a a rolling speed but in this case it slides works really well oh i can't get up there so that's it we've got the all the animations are working there now in the next video um i will probably rewrite some of this stuff and and and see if i can change this from a lerp to move towards i think there is a an option here called move towards move toward move from toward two by the delta value and it should return it should work better it should get down to zero and i shouldn't need to do that little thing where i round it down to zero if it's less than 20 or 30. that will i'll have a look at that but another thing i want to do is add some other animations such as the attack animation and a hanging animation so actually hanging on the edge of something which should be fairly simple we just need a separate collision shape that's kind of above where and that will hook onto the edge um and we'll then we'll change if that's colliding with the ground and so on then we'll we'll change the animation so that'll be another thing that we will look at in another video but this video has been long enough so i hope this hope this has been helpful hope maybe it's a little bit different to some of the other good old platform tutorials out there in that it's kind of looking at a state machine but the code here i think it's pretty simple i don't think i've made it overly complex we've got the update animation we've kind of separated the visual side of things from the physics side of things which is what we should do and uh kept it all fairly straightforward let me know if you enjoyed this video in the comments below
Info
Channel: LukeRS
Views: 2,396
Rating: undefined out of 5
Keywords:
Id: MpyEE1pKdeI
Channel Id: undefined
Length: 33min 25sec (2005 seconds)
Published: Sun May 23 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.