How to deal with SLOPES! in Unity 2D using built in Physics

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
what is up guys welcome to Barden my name is Heinrich and today we're gonna take a look at how we can handle slope using unities built in physics and rigidbody 2d components it's gonna look something like this we can move up and down slopes the character will stick to the surface and we can even specify a max angle that the character can move up like that it'll look something like this okay so let's just get into it okay so we'll start off with this scene the project as it is now allows the character to move left and right and jump when it push space it's a very simple little character controller in the scene we have a super basic player that has a super basic playercontroller script connected to it if we open up this controller script we can see what is happening all the script is doing right now is moving the player left and right based on our horizontal input flipping the player based on movement direction and checking ground and making it so the character can jump I will include the project as it is right now in the description if you want to work along but if you already have a movement script you should be able to apply the slow code to your own script okay so let's first talk about how we're actually going to handle the slopes we're going to cast array from the bottom of the players capsule Collider this Collider will detect ground and it will also detect the normal of that ground so with this information we can tell if the ground is at an angle or not we are then going to adjust the character's velocity to move it along the ground we'll also then detect corners in the slopes or where the slope changes and then adjust the velocity accordingly to keep the player stuck to the ground we also need to make it so that if the character is standing still on the slope he doesn't get pulled down by gravity and slowly slides down the way we're going to fix this is by just changing the physics 2d material of the player when he's standing still to something that has a high friction okay so the first thing we need to do is determine the position where we want to fire the Ray from we're going to fire it from the very bottom of our capsule Collider right here so you could create an empty child game object and place it at that point and just reference that in the code but we can also find this point in code using a little bit of math let's jump into our code and let's start off by getting a reference to our capsule Collider so we'll say private capsule Collider 2d and I'm just going to call it CC in our start function we can then get this reference so we'll say CC equals get component off type capsule Collider 2d just like that next we want to store the size of the capsule Collider the size is given as a vector two so let's come and declare a new vector 2 and we'll just call it collider size in the start function we can then say collider size and equals CC dot size next let's declare a function called slope check so Bob our check input will say private void slope check like that this function is going to get cold in our fixed update after check ground like that in our slope check we're going to start off by determining that position at the bottom of our collider so we'll say vector 2 and we'll just call it check position we'll set this equal to transform dot position - the colliders Y size and to do this we need to create a new vector 3 and for the X we will use zero point zero F and for the Y we'll use a lighter size and divide it by two my shits Collider size dot Y divided by 2 from this position we're going to do a check down and to the front and to the back so right two more functions one for the horizontal slope check and one for the vertical slope check so let's start with the horizontal so say private void and we'll call it slope check horizontal like that and now we're going to actually pass this check position to this function so this function has an input parameter that is of type vector two and we'll just call it check position again next we have private void slope check vertical which also takes in the same vector two like that before we do anything in these functions let's head back to unity and actually create some slopes that we can try moving up and down to easily make different angle slopes if you want to use a tile map you can go to the sprites folder and say create new sprite and create a polygon sprite in the sprite editor you can then select three as the number of sides and then hit apply you can then come to the custom outline and then just drag it to the bottom left bottom right and top right corner and then hit apply you can then come to the custom physic shape and then just do the same for these extra points if you click and drag them and then hit delete it'll delete the point you can then hit apply again and now we have a slope we can come to our tile palette and then just drag the slope in and then go to art on maps folder and the assets folder and then just save it there we can now paint some nice little slopes into our scene I'm gonna go ahead and create the sprites for another slope that has a slightly smaller angle and then just add these to my tile palette as well okay say we now have two different angled slopes that we can use just like that okay let's jump back into the code and see if we can detect these slopes so in our slope check vertical function we'll start off by declaring a ray cast hit 2d and we'll just call it hit this is gonna store what our vertical ray cast hits we'll set this equal to physics 2d ray cast and for the origin we're going to use this check position that we calculated and the direction is going to be vector to dump down we then you to come up and declare another variable that's going to be the slope check distance so we'll come up to our sear lies field floats will say serialize field and this is a private float called slope check distance we can then come back to our function and pass that as the distance and then finally we can pass in the what is ground layer mask that has already been declared beforehand next we can say if this ray cast actually hit something so if hit then we want to debug dot draw ray and we'll draw it from hit that point and this is the point where our ray cast intersects the collider and the direction is going to be hit dot normal hit on normal returns the normal of the collider that has been hit after this we can specify a color for it so you can say color dot and I like to use green for my normals so if we save this and then make sure that in our slope check function we call slope check vertical and pass it or check position again save this and then head back into unity and then make sure that in our player game we specify a slope check distance I'm going to start off by specifying zero point five and then we run this and as you can see if i zoom in here there's this little green line that indicates the normal of the ground we are standing on and then if we start heading up a slope you can see the Green Line points away from the slope at a 90 degrees okay so let's head back into our code so now we can do is we can store the angle of our slope and we can also store the perpendicular vector to of our normal so let's come up to our variables and let's declare a private float that we will call slope down angle we're specifying down because it's our ray cast that's shooting down and then we can also declare another private vector - that will call slope normal perpendicular and I'll just say perp for that back in our function we can start off by saying slope normal perpendicular equals vector 2 dot perpendicular so this is a function that the vector 2 class has where we can pass it a vector - and it'll return a vector - that is perpendicular to the vector - that we gave it in a counterclockwise direction so if we pass this hit dot normal then it should return a vector to that points to the left when we are on flat ground next we can get the angle so we'll say slope down angle equals vector - and we can use another handy built-in function called angle and to this we can pass hit dot normal and vector to up so this will return the angle between the y-axis and our normal which just so happens to be the angle between our x-axis and our slope next let's just draw our perpendicular as well with debug the drawer a and this time we pass it hit dot point as well and the direction is slope normal perpendicular and the color will just make red color dot red so if we save this now head back into unity and then run the game you can see we have a red ray indicating the perpendicular to our normal if we start heading up the slope you can see it points down the slope we'll use this to determine what direction we should be applying our velocity in okay so next we just want to declare a boolean that is going to keep track if we are currently on a slope or not so say private bool and we'll just call it is on slope we also want to come up and declare another private float that will call slope down angle hold back in our function we'll say if our slope down angle does not equal our slope down angle old then is on slope equals true and after this we want to say slope angle old equals slope angle while slope down angle next we want to come down to our apply movement function currently all we're doing is we are creating our movement vector two and then applying our movement vector two as a velocity instead we're going to have to have three different ways of applying velocity one for if we are on flat ground one for if we're on a slope and one for when we're in the air so let's start off by just writing those three different if stations with the first one being if we are on the ground and not on a slope so we'll say if is grounded and we're not on a slope then we want to apply a specific kind of velocity and we'll see else if we are grounded and we are on a slope we want to apply a different kind of velocity and then lastly else if we are not grounded apply the last kind of velocity so the last one is if we're just in the air so we'll start off by saying new velocity dot set and we'll say movement speed multiplied by X input and then for y we'll just say our B velocity dot Y we then need to set this velocity with our B dot velocity equals new velocity for when we're on the ground and not on a slope it's fairly simple as well we'll start off by saying new velocity dot set and this time for the X it's the same so movement speed multiplied by X input and for the Y this time we're gonna say zero point zero f and then apply the velocity like that we'll just make this look a little bit better okay so now when we're on the slope we want to apply the velocity specifically in the direction of the slope so we'll say new velocity dot set so say movement speed multiplied with slope normal perpendicular dot X multiplied by negative or X input and we're using negative X input in this case because of the way our slope normal perpendicular is being determined and then for the Y we'll use movement speed multiplied by slope normal perpendicular Y multiplied by negative x like that and then we just need to apply the velocity I forgot something when we were determining the perpendicular vector to and over here we just need to say dot normalized that way our vector two has a magnitude of one and then when we're moving up the slope will keep the same velocity so if we save this and try it out you can see it's already looking a lot better but let's check out some more possible slopes that we might have let's come to our tile palette and let's just paint a couple of spikes like fat let's see what happens when we walk on those as you can see when we reach the top we still bounce we don't go back down the slope it's checked over here here we stick to the slope a bit better because it's not such a drastic change so let's go ahead and fix that let's head back to our code and now we're going to work on the slope check horizontal function I should start off by remembering to call this from our slope check function like that and in the slope check horizontal function we're going to have two raycast hit two DS one for the front ray and one for the back Ray so ray cast hit 2d I'll just say slope in front have another ray cast hit 2d called slope hit back like that and we can start off by setting the first one equal to physics 2d dot ray cast and we're going to use check position as our position transform dot right as our direction slope check distance as our distance and what is ground as our layer mask and then the second one is going to be exactly the same except we're going to use negative transform the dock right as our direction just like that okay next we can come back up to our variables and declare another prime float and this time it's just going to be slope side angle back in our function we can start off by saying if slope hit front so that means the ray pointing in direction our character is facing is detecting a slope we will say is on slope equals true and then we'll set our slope side angle equal to vector to angle from slope hit front dot normal to vector to up and then we can say else if instead our back ray has hit something so if slope hit back then is on slope this is also equal to true and our slope side angle equals vector to angle and this time it's going to be slope hit back dub normal and vector chewed up again and then finally we can say else if neither of those rays are detecting something we can say slope side angle equals zero point zero f and is on slope equals false so if we save this and then head back into the game and run it you can see that we stick to the slope wonderfully now before we continue I must explain that this way of dealing with slopes is going to be consistent but it's not going to work 100% of the time and that is just because of the way the unity physics system works and the only way we're going to get better results is by using custom physics and the reason it doesn't always consistently work is because of if we are at the edge of a slope and we're about to move over the slope depending on how far our character moves in the next update will determine how well it sticks to the slope now usually depending on how fast your character is actually moving it's going to be fine but you're gonna get those rare cases where in our current frame we are right at the edge and then in our next frame we're quite a bit away from the edge so we'll have a little bit of a bounce but generally that should not be an issue especially for slower moving characters and for slopes that don't have such drastic changes and angles like we have here okay so now let's head on to the next issue and that is the fact that our character slides down the slope when we don't want it to so to do this we're going to come to our physics materials folder and we're just going to create a new physics 2d material or a physics material 2d that we'll call full friction and then in the inspector for this material will change the friction to just it and that's going to change it to the highest friction that we can you can come back to our code and let's declare two new variables they're both going to be serialize fields and they are private physics material 2d and the one is going to be no friction and the other one is going to be full friction let's just save this and head back into unity and drag in these references before we forget so full friction goes in the full friction slot and zero friction goes in the zero friction slot we can then jump back into our code and go to our slope check vertical function after this if statement will say if is on slope and our x input is zero then we can change the physics 2d material of our rigidbody 2d to our full friction material we do this by saying our be shared material and then we can just set it equal to full friction and then we can say else our b dot shared material equals no friction like that if we head back to unity and then run the game oh when dragging in your references make sure that your game is not currently running so let's drag full friction back into full friction and zero friction into zero friction and then run the game as you can see when we stop moving the character sticks to the slope and basically it's working now next we just need to take care of fixing our jump functions if that works and then we also need to make it so that we can set a max slope angle so let's stop this and let's start with the jump we'll start off by declaring a new boolean we'll call it is jumping we can then come to our jump function and set is jumping equal to true in our apply movement function we can then add not is jumping to our first two if statements so and not is jumping and then and not is jumping we then need to just take care of setting is jumping back equal to false at the appropriate time such do this we'll come to our check ground function in here we're currently saying if the character is grounded and our rigidbody dot philosophy that Y is less than or equal to 0.01 F can jump gets reset to true that just makes it so that we can't jump infinitely and there can only jump once we've touched the ground again so we're gonna change this around a little bit by saying if rigidbody dot velocity Y is less than or equal to zero point zero F then set is jumping equal to false because now we're no longer jumping but instead we are falling and then in this if statement below it instead of using orbital Asiata Y in here we're just going to use not is jumping so if we save this head back to our game and test it out you can see that a character can jump again you can even jump on the slopes okay now let's deal with the max slope issue let's head back to our script and let's start off by declaring a variable where we can store our max slope angle so we'll make another serialize field private float that will call max slope angle we can then also come down to our private boolean's and create another private pool that is going to be called can walk on slope so is on slope will get detected even if the slope angle is too big but we'll just turn can walk and slip off so that we can no longer walk on that slope let's come back to our check slope vertical function and before we do this whole friction thing let's say if our slope down angle it's greater than our max slope angle then we can set can walk on slope equal to false else we'll set and walk on slope equal to true and then after this where we set the friction let's add another condition in here that is just can walk on slope is equal to true because if we don't give any input on a slope that has too steep of an angle we want the friction to be zero so that we slide down it let's go back down to our apply movement function and then just add a can walk on slope as a parameter for the second or for the first else if so if we save this and head back to unity this first slope over here should have an angle of 45 so let's set our max slope angle that means we should not be able to walk up the second slope so don't be dumb like me and remember to remove these two lines of code because we don't want to apply a velocity of none of these ifs are met so if we hop back to the game now and try it out as you can see we can not move up the steep slope we have another little issue though as you can see we don't slide all the way back down there's this little space over here and this is due to the distance of our slope check so so the steeper the slope that we're trying to go up the bigger this distance is going to be because the faster this ray is going to detect flat ground again which is technically a walkable slope so to fix this let's head back to our code and in the part where we set can walk on slope we're going to set it to false if slope down angle is greater than max slope angle or our slope side angle is greater than max slope angle like that so if we save this and head back to unity as you can see we slide all the way back down now okay now we have one more issue when we jump onto a slope that is technically too steep for us to walk on we can still jump so we can still climb up this slope like that to fix this all we need to do is in the part where we set can jump back equal to true so in our check ground function we just have to add and slow down angle is less than or equal to max slope angle just like that so if we run it now you can see that our characters can no longer jump when he's on an angle that's too steep and that's it we now have a character that quite reliably sticks to our slope surface and we can even specify slopes that are too steep for our character to climb I hope you guys manage to learn something from this tutorial and somehow manage to implement this into your projects I was planning on adding slopes to my main tutorial series but it's just adding a little bit too much overhead for everything else like the enemy AI and some of the movement abilities that the character has that I don't feel like dealing with right now so I most likely will be implementing slopes into that game eventually but first there's some other more important things that I want to focus on before I rework the character and optimize it and then add slopes in at that point I would like to thank everybody on the discord server who voted for this topic I'm sorry it took so long to come out it was quite a lot more work getting this to work than I thought it would be and I would also like to thank my supporters on patreon and also the wonderful people on patreon and then lastly a big special thank to Lewis for your support on patreon I hope you all stay safe during this peculiar time that we're having and I also hope that you all have a wonderful day
Info
Channel: Bardent
Views: 74,832
Rating: undefined out of 5
Keywords: unity, slopes, rigidbody2d, no, custom, physics, not kinematic, character, controller, vector2, easy
Id: QPiZSTEuZnw
Channel Id: undefined
Length: 30min 7sec (1807 seconds)
Published: Mon Mar 23 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.