*NOTE/CORRECTION:* Someone pointed this out to me, but there can be a case where you can't jump when running up stairs. Also if you use velocity.y += jump_velocity for your jump instead of velocity.y = jump_velocity, it can cause you to stick to the stairs charging up your y velocity to go flying after. I added this small fix to check if velocity.y > 0 before snapping up stairs which ensures the character won't snap up the stairs if jumping & walking forward. You can incorporate this fix into your stair code as well: github.com/majikayogames/SimpleFPSController/commit/ba3499cb6eda147175a141391276b2976428dfd7
Your tutorials have so much substance! Not one of those "how to get started", but "how to get something polished". Thank you for putting these together!
Can I say thank you honestly there aren't many tutorials on this and I hope you keep adding to this controller. I'm also so glad you keep it simple and not using 100's of scripts using state machines third party plugins etc which yes are good, but at the same time if you are just trying to learn one part you are hunting through the video trying to understand the part they are typing and if it's using things from other scripts this is perfect for people that want to learn how these problems are tackled and solved. ❤❤❤❤
Appreciate the comment :) Indeed I will be adding a bunch more features I'm going to add to this character controller. Going to release a bunch more videos very soon on it, probably in the next few days.
Delicious, solved my problem of unintentional ledge grabbing on jump. Thank you for sharing your knowledge, very appreciated. Another step taken in my new hobby of fiddling with coding.
If you plan to use Stairs inside of a GridMap3D node, you can swap out CSGMesh3D with GridMap or add it as a 3rd check instead like this: and (down_check_result.get_collider().is_class("StaticBody3D") or down_check_result.get_collider().is_class("GridMap") or down_check_result.get_collider().is_class("CSGShape3D"))):
Here is a tip if your downstairs movement is working but upstairs is not. CHECK SPELLING. I was trying everything to figure out why I couldn't go up. I misspelled "CSGShape3D" in the class check. I spelled it "CGSShape3D". Just in case someone is having the same problem.
This is a fantastic series of courses that I've learned a lot from. I hope the author can add a tutorial about foot joints and slopes, aimed at preventing the feet from exceeding the model when a character walks on a slope and allowing them to align with the slope's angle. I believe many people need this; it's probably called IK (Inverse Kinematics).
Always love seeing the ways people dive into character controllers. Consider that with your single raycast you cannot walk backwards upstairs, or strafe upstairs. An alternative method is to do three "move and slides." i.e. get "wish" direction, then move the player up, then along the wish direction, then down. You have to then potentially revert that movement if you didn't hit anything. (while I'm commenting - I also want to add that I hate capsule colliders because when you walk near the edge of objects you sort of fall off but no really. counter strike uses a box collider I believe)
Ah do they? I was actually trying to find what collider shape is used in CSS but I couldn't find anything. I also find that annoying about the capsule shape lol. Also - the raycast is rotated later in the code so it will allow walking up stairs. The method you described is basically what I do here I think, I run a body test motion in front at the expected pos next frame based on velocity, and slightly above, shooting downward. If it collides at feet safely on a flat surface (that's what the raycast checks) character will be moved there.
@@MajikayoGames Oh very nice. Obviously I skipped around in the video :'). Yes I think you're basically doing what I suggested. Maybe also consider a shapecast instead of a raycast. Will be following!
So, I got up and down movement to work just fine with one small issue. I'm still flying off the stairs sometimes going down. Not every time but every 1/10 times. And it's usually when sprinting. Maybe the check isn't fast enough to catch when you go too fast?
you might try increasing the length of the stairs below raycast3d. i think i had this problem, i noticed extremely rarely i could bounce off stairs. worst that will happen if it's too long is slight jitter stepping off some things.
@@MajikayoGames I tried to change it to -1m instead of -0.75 and it stopped working altogether. I soon realized I changed it to 1 instead of -1 and I felt dumb. It works every time now. lol
This is a really nice implementation, though I am contending with some jitter in my project due to the CameraSmooth node following the CharacterBody3D up/down the step before snapping back to perform its move_towards() function in the next frame. I've experimented with changing the delta around, but to no avail. Any ideas?
The camera smooth function should be called as the last thing in the physics process, after either stair up/down snap function has been called. If you put it before, that would mean it would snap back the frame after we already moved & rendered the frame to the screen, likely resulting in jitter. So _slide_camera_smooth_back_to_origin should be called every physics process frame after everything is done. If that is what you mean by performing move_towards next frame.
great video! but im getting an "Invalid operands 'Transform3D' and 'Vector3' in operator '+'" error in "self.global_position = step_pos_with_clearance + down_check_result.get_travel()" in _snap_up_stairs_check, any idea how to fix this?
step_pos_with_clearance is a Transform3D() while global_position and down_check_result.get_travel() are Vectors for just position. you need to use step_pos_with_clearance.origin
Having a rather specific and weird issue. For some reason whenever I walk up the right half of a CSGStair, I will around half the time just not snap up. I do, however, consistently snap up when walking up the left half of a CSGStair. Using the debug settings to show collision shapes it shows that the raycast somehow ends up all the way to the left of the CSGStair (Going so far left it seemingly falls outside of the stair itself) which I really can't explain. I do have some differences from the way you did it, mainly I have a cylinder instead of a capsule collider. However, code wise for the snap up code that just means that I had to remove the "step_height
Have you found a solution to this? I've ran into the same problem now, but I've narrowed it down to the following if statement: if step_height > MAX_STEP_HEIGHT or step_height MAX_STEP_HEIGHT: return false For whatever reason, something in this if statement doesn't like it when you hug a stairwells wall and about to meet the top of the stairs. One difference that I'm getting from your description, I'm able to reproduce the bug no matter the side the wall is on. I'm seeing a possible solution under @sabertooth9137's comment, but the op says it still could lead to problems with angled walls? I'll look into this a bit more on my own, I'll post a update here if anything crops up. Edit: Something of interest, the collision shape matters for how noticeable this anomaly is. Boxes and capsules get caught on this predicament much sooner than when using cylinders. Regarding the problematic if statement, "step_height > MAX_STEP_HEIGHT" and "(down_check_result.get_position() - self.global_position).y > MAX_STEP_HEIGHT" are both being met, causing this loathsome issue. One last thing I saw, these conditions get reserved for a split second whenever walking backwards off a step, but only very rarely. No clue why, but it doesn't have a noticeable effect really so its not particularly important I imagine.
@gamingcam2008 I've yet to find a solution, decided for the mean time to move on and have just left a note to fix it later. If it's possible, maybe trying to run the check twice like I do when going down something is worth trying? Can't remember if I tried it already
@@Zeraph-Zen I've tried running the check but rotating the motion vector left/right and going with whatever works first, but I don't think I'm grasping the vector math at play here cause nothing I've done has worked properly. I'll get back to this another day, I made it somewhat better by reducing my max step height (I had set it to 0.5 when I first set up my movement variables??? I may be stupid!) T.Y. for the response!
The SeparationRayShape3D solution has sounded preposterous to me for a long time, but... recently I noticed that Thief has used this method (well, 99% similar), and it actually never really bothered people much. There are of course a few issues, but it's not as bad as I thought, and for some games it's not really a problem at all. For example, I'm considering using it for horror games that don't require much ground precision. I just need to learn how to make it stick to the floor when climbing down steps, as well as how to smooth the camera. This method actually has a couple of upsides: it's simple (I think), and it prevents climbing on wall baseboards, and things of that nature. If I had a dollar for every time I had to create clip brushes in maps I made to prevent players from inadvertently climbing onto such things...
Hey this tutorial has been exactly what i have been looking for thank you sir, i just have a question. Im porting this to 2D and when you set the expected motion variable to multiply delta by x and z, you say this is a 'forward' motion but I thought that the Z axis is the one which controls back and forth movement and the X is for left or right, can anyone help clarify? I appreciate it
Y is up, so i multiply by Vector3(1,0,1) which will set/multiply Y by 0. and leave X and Z the same. just interested in the horizontal move direction, yes as you said, that is X and Z. if this was in 2D, then you could do something like *Vector2(1,0) as you are only interested in horizontal movement, towards the stairs. but horizontal in 2D is only X as there is no Z dimension. you may have to get a bit creative in adapting it but the general concept is to simulate where the player would be, whichever way they are stepping, towards a stair for example, and then shoot a shape cast/body test motion down from slightly above to see if there is some stair there. if it hits and it is not too high of a jump, then you can let them step up.
Thank you for the reply! This helped me get on the right track as I barely had to change any code for correct function. I thought it wasn't working because of that direction variable but it was simply some values and checks which had to be switched around to negative for the y axis lol, I'm still very much a novice at this so thank you again.
Amazing tutorial! I encountered an issue where, for some reason, my camera smoothing node's x and z values were being changed. My manually resetting them via code, seems to have fixed the issue.
Hi this method for handling stairs is really good, thank you for the tutorial! I'm having one issue though. When my controller is moving against a wall and then slides towards steps it should be able to climb over it gets stuck and only updates the position of the character up the stairs when I stop moving. Any idea on how this could be fixed?
Your solution is really clever and works great, though I had a couple of issues; If your movement speed is too slow it is not able to snap up the stairs and starts jittering up and down. I think this is because the translation distance is not sufficient enough at such a small velocity and the capsule simply slides back down, at least for my capsule size (radius of 0.2m). Is there a way to add a minimum velocity clamp to the expected_move_motion function? The other issue i encountered was the camera smooth would have it's position moved on the z and x axis's when going down the stairs. Adding move toward code similar to the y axis solved this, but I was wondering if you or anyone else had this issue?
for the first part, you might try using a box shape instead of a capsule. i was thinking about switching my character controller to use a box instead, because of this issue where you can kind of be half on the floor sliding off it. if when walking up the stairs the character stops you can get caught slowly sliding down an edge like this and not technically be 'on floor'. for the camera smooth, im not sure what you mean. i have mine set up so it only ever drifts it along the y axis. this makes sense to me because the horizontal speed is constant going up/down stairs as it is moving on floor. so just always move with character xz. also less glitchy with headbob that way from some testing i noticed.
@@MajikayoGames Thanks for the reply, what I ended up doing was removing the camera smoothing all together an instead interpolate my characters position between the steps instead. multiplying the interpolation speed by the step height and move speed also helped. Applying this technique to the snap down too. And of course switching to a box collider too :)
i was using your tutorial to help with the stairs. i saw the _physics_proccess function and from fear that my code was missing something important i got into writing it down. Well my stupid but realized that this function is the exact same as the one i already have. Always preread before typing it down ig
This is an incredible and exceptionally well-explained solution! Thank you so very much, MajikayoGames. I'm ecstatic to have completed this great tutorial and I can't wait to see what else you've got and what's coming next.
This tutorial is very well made, however I am having trouble getting the going up the stairs check to work, so the player doesn't start going up the stairs. The down check works perfectly, but the going up check is causing issues for me. I followed your video exactly and compared mine to the github version and I'm not sure what's happened to make mine not work. I could send you the script if you want, but its pretty much the same as yours as I am trying to get a base for the movement.
after running through diffchecker i think i changed a down_check_result.get_position() to a down_check_result.get_collision_point() great tutorial, works great now!
hi, im having an isue with the camara smoothing where, the higher up on the node tree i assighn the smoothing too when going down steps the more the camara sinks into the floor, and the lower on the node tree the higher the camra floats into the sky, all of the postions of these nodes are 0, 0, 0.
It's hard to say without looking at your code, but another person had a very similar problem, the solution ended up being the node structure and position. The head original position should be moved, and the rest stay at 0,0,0. If you have double checked your code and it's just like mine, i would think it's a similar thing. Are you sure the nodes are exactly the same as mine?
@@MajikayoGames it's not quite the same I have the character body witch is at 0,0,0. Then a body node also centered then a heads node that is moved up, and then a head 1 node that is centered and then the Camara node. The one I am smoothing is the head 1 node. One more thing to note is that the camera is not only drifting vertically but also horizontal. For now I just got rid of the camera smoothing and I plan to lerp the velocity down the stairs
@@zeepnely5678 Gotcha if you have your own setup, it may need some different code. This method is designed to be used with the exact same node and positions setup i have.
Can't think of why this would happen. Do you mean you fly up in the air? Check my pinned comment, it may be due to y velocity accumulating when sticking to stairs. Just make sure you are not calling snap up stairs if y velocity is positive
@MajikayoGames Thx for the quick response! I don't get flung upwards, it's if I press jump I go up and don't come back down, I just float 😭 it only happens after going up or down stairs, the jumping works before then
Interesting question, right now I'm focusing on just doing a player script, but just as CSS has bots which will move by the same laws of physics & rules as the normal players, we could adapt this to be used for a bot script. For that, we would basically just simulate the player input. We might have to abstract the input layer a bit more, so the bot can essentially send fake inputs, depending on some navigational AI. I think the movement wouldn't be that hard, as we already have wish_dir variables which are just set to input. Instead of keyboard input, we would just look to the nav agent's instructions for the wished move direction. I'll write this down as an idea for a future tutorial as this could be pretty interesting I think. Thanks :)
Oh also, I realized you probably mean allowing bots to walk down stairs specifically. I haven't looked into that exactly, I would have to look into how navmesh works. If using godot's built in version, it would probably take some fine tuning, but I would think you would bake the nav mesh with the agent_max_climb set to the same height/slightly great than the max step height of your player. And it might take some tuning but I'm guessing something like above would work.
@@MajikayoGames Yeah been having quite some difficulty figuring out all the navregion properties to create the perfect navmesh that can handle stairs (with non ramp collision) and and holes like doors and such. I think if you made a tutorial for it would be a fun (and maybe somewhat frustating xD) challenge and it would definitely be the only one on YT.
@@mrjshzk added it to my list of tutorial ideas :) i do like doing unique videos as they seem to get the most views. No competition i guess if im the only one making a video on a particular topic. I would probably be doing it a bit later in the series as i have a lot more tutorials to get through though
Very Geat tutorial. I works very good for me. Also, I have noticed when I try to walk up the stairs while im sided by two walls and face to the wall slightly i will stop moving. If I face staight i will work but being some angles off it will not. Do you know why this is happening and how I could fix it? If you dont no problem. And thank you for the tutorial it realy helped me.
Its because the code spawns the raycast basically at the spot where you would collide if you walk ahead at a higher level to calculate the step height. In your case you collide with the walls before the stairs - spawning the raycast in there and not allowing you to go further because the step height is at its limit. Got the same problem no idea on how to solve it though XD.
@@sabertooth9137 I played around a bit and i think i might have something that works now. It still isnt that great if you walk in a large angle towards a wall (as in 45 degrees for example) but at least its something. Try it if you want - its basically just making more test moves at angles if the collision happens at an unexpected height if (self.test_move(step_pos_with_clearance, Vector3(0,-MAX_STEP_HEIGHT*1.3,0), down_check_result) and (down_check_result.get_collider().is_class("StaticBody3D") or down_check_result.get_collider().is_class("CSGShape3D"))): if down_check_result.get_position().y > step_pos_with_clearance.origin.y: var raycast_left_pos = self.global_transform.translated(expected_move_motion.rotated(Vector3(0, 1, 0), deg_to_rad(20)) + Vector3(0, MAX_STEP_HEIGHT * 1.3, 0)) self.test_move(raycast_left_pos, Vector3(0,-MAX_STEP_HEIGHT*1.3,0), down_check_result) if down_check_result.get_position().y > step_pos_with_clearance.origin.y: var raycast_right_pos = self.global_transform.translated(expected_move_motion.rotated(Vector3(0, 1, 0), deg_to_rad(-20)) + Vector3(0, MAX_STEP_HEIGHT * 1.3, 0)) self.test_move(raycast_right_pos, Vector3(0,-MAX_STEP_HEIGHT*1.3,0), down_check_result) var step_height = ((step_pos_with_clearance.origin + down_check_result.get_travel()) - self.global_position).y (gotta change the clearance amount if you want to have Max_step x 2)
nice job. I use shapecast for step checking. And I give up on using Physics test. Positioning of shapecast or raycast is important if you want to add crouch
*NOTE/CORRECTION:* Someone pointed this out to me, but there can be a case where you can't jump when running up stairs. Also if you use velocity.y += jump_velocity for your jump instead of velocity.y = jump_velocity, it can cause you to stick to the stairs charging up your y velocity to go flying after. I added this small fix to check if velocity.y > 0 before snapping up stairs which ensures the character won't snap up the stairs if jumping & walking forward. You can incorporate this fix into your stair code as well:
github.com/majikayogames/SimpleFPSController/commit/ba3499cb6eda147175a141391276b2976428dfd7
Your tutorials have so much substance! Not one of those "how to get started", but "how to get something polished". Thank you for putting these together!
Appreciate the comment from a returning viewer 😄😄Glad I can keep making content you enjoy and find useful. More to come soon.
this is the best tutorial series ever. I would have given up by now on a normal tutorial but you make it so easy to understand
Can I say thank you honestly there aren't many tutorials on this and I hope you keep adding to this controller. I'm also so glad you keep it simple and not using 100's of scripts using state machines third party plugins etc which yes are good, but at the same time if you are just trying to learn one part you are hunting through the video trying to understand the part they are typing and if it's using things from other scripts this is perfect for people that want to learn how these problems are tackled and solved. ❤❤❤❤
Appreciate the comment :) Indeed I will be adding a bunch more features I'm going to add to this character controller. Going to release a bunch more videos very soon on it, probably in the next few days.
Delicious, solved my problem of unintentional ledge grabbing on jump. Thank you for sharing your knowledge, very appreciated. Another step taken in my new hobby of fiddling with coding.
If you plan to use Stairs inside of a GridMap3D node, you can swap out CSGMesh3D with GridMap or add it as a 3rd check instead like this:
and (down_check_result.get_collider().is_class("StaticBody3D") or down_check_result.get_collider().is_class("GridMap") or down_check_result.get_collider().is_class("CSGShape3D"))):
Here is a tip if your downstairs movement is working but upstairs is not. CHECK SPELLING. I was trying everything to figure out why I couldn't go up. I misspelled "CSGShape3D" in the class check. I spelled it "CGSShape3D". Just in case someone is having the same problem.
excellent tutorial I appreciate that you take time to show documentation and do more show than tell.
This is a fantastic series of courses that I've learned a lot from. I hope the author can add a tutorial about foot joints and slopes, aimed at preventing the feet from exceeding the model when a character walks on a slope and allowing them to align with the slope's angle. I believe many people need this; it's probably called IK (Inverse Kinematics).
Glad to hear! I'm also interested in IK/procedural animation. I'll write that down as a potential video topic.
Always love seeing the ways people dive into character controllers.
Consider that with your single raycast you cannot walk backwards upstairs, or strafe upstairs. An alternative method is to do three "move and slides." i.e. get "wish" direction, then move the player up, then along the wish direction, then down. You have to then potentially revert that movement if you didn't hit anything.
(while I'm commenting - I also want to add that I hate capsule colliders because when you walk near the edge of objects you sort of fall off but no really. counter strike uses a box collider I believe)
Ah do they? I was actually trying to find what collider shape is used in CSS but I couldn't find anything. I also find that annoying about the capsule shape lol. Also - the raycast is rotated later in the code so it will allow walking up stairs. The method you described is basically what I do here I think, I run a body test motion in front at the expected pos next frame based on velocity, and slightly above, shooting downward. If it collides at feet safely on a flat surface (that's what the raycast checks) character will be moved there.
@@MajikayoGames Oh very nice. Obviously I skipped around in the video :'). Yes I think you're basically doing what I suggested.
Maybe also consider a shapecast instead of a raycast.
Will be following!
Hell yeah! Your original was a great solution, but now it's even better!
thank you :D I like your profile picture
So, I got up and down movement to work just fine with one small issue. I'm still flying off the stairs sometimes going down. Not every time but every 1/10 times. And it's usually when sprinting. Maybe the check isn't fast enough to catch when you go too fast?
you might try increasing the length of the stairs below raycast3d. i think i had this problem, i noticed extremely rarely i could bounce off stairs. worst that will happen if it's too long is slight jitter stepping off some things.
@@MajikayoGames I tried to change it to -1m instead of -0.75 and it stopped working altogether. I soon realized I changed it to 1 instead of -1 and I felt dumb.
It works every time now. lol
@@PastaMaster115 happens to the best of us :)
Great tutorial! Thank you! It helped me a lot. Only left to fix animation issues due to my 3d person controller
This video is an answer to my prayers. 🙏
Thank you.
This is a really nice implementation, though I am contending with some jitter in my project due to the CameraSmooth node following the CharacterBody3D up/down the step before snapping back to perform its move_towards() function in the next frame. I've experimented with changing the delta around, but to no avail. Any ideas?
The camera smooth function should be called as the last thing in the physics process, after either stair up/down snap function has been called. If you put it before, that would mean it would snap back the frame after we already moved & rendered the frame to the screen, likely resulting in jitter. So _slide_camera_smooth_back_to_origin should be called every physics process frame after everything is done. If that is what you mean by performing move_towards next frame.
great video! but im getting an "Invalid operands 'Transform3D' and 'Vector3' in operator '+'" error in "self.global_position = step_pos_with_clearance + down_check_result.get_travel()" in _snap_up_stairs_check, any idea how to fix this?
step_pos_with_clearance is a Transform3D() while global_position and down_check_result.get_travel() are Vectors for just position. you need to use step_pos_with_clearance.origin
@@MajikayoGames sorry I missed that, thank you!
Having a rather specific and weird issue. For some reason whenever I walk up the right half of a CSGStair, I will around half the time just not snap up.
I do, however, consistently snap up when walking up the left half of a CSGStair.
Using the debug settings to show collision shapes it shows that the raycast somehow ends up all the way to the left of the CSGStair (Going so far left it seemingly falls outside of the stair itself) which I really can't explain.
I do have some differences from the way you did it, mainly I have a cylinder instead of a capsule collider. However, code wise for the snap up code that just means that I had to remove the "step_height
Have you found a solution to this? I've ran into the same problem now, but I've narrowed it down to the following if statement:
if step_height > MAX_STEP_HEIGHT or step_height MAX_STEP_HEIGHT: return false
For whatever reason, something in this if statement doesn't like it when you hug a stairwells wall and about to meet the top of the stairs. One difference that I'm getting from your description, I'm able to reproduce the bug no matter the side the wall is on. I'm seeing a possible solution under @sabertooth9137's comment, but the op says it still could lead to problems with angled walls? I'll look into this a bit more on my own, I'll post a update here if anything crops up.
Edit: Something of interest, the collision shape matters for how noticeable this anomaly is. Boxes and capsules get caught on this predicament much sooner than when using cylinders. Regarding the problematic if statement, "step_height > MAX_STEP_HEIGHT" and "(down_check_result.get_position() - self.global_position).y > MAX_STEP_HEIGHT" are both being met, causing this loathsome issue. One last thing I saw, these conditions get reserved for a split second whenever walking backwards off a step, but only very rarely. No clue why, but it doesn't have a noticeable effect really so its not particularly important I imagine.
@gamingcam2008 I've yet to find a solution, decided for the mean time to move on and have just left a note to fix it later.
If it's possible, maybe trying to run the check twice like I do when going down something is worth trying?
Can't remember if I tried it already
@@Zeraph-Zen I've tried running the check but rotating the motion vector left/right and going with whatever works first, but I don't think I'm grasping the vector math at play here cause nothing I've done has worked properly. I'll get back to this another day, I made it somewhat better by reducing my max step height (I had set it to 0.5 when I first set up my movement variables??? I may be stupid!)
T.Y. for the response!
The SeparationRayShape3D solution has sounded preposterous to me for a long time, but... recently I noticed that Thief has used this method (well, 99% similar), and it actually never really bothered people much. There are of course a few issues, but it's not as bad as I thought, and for some games it's not really a problem at all. For example, I'm considering using it for horror games that don't require much ground precision. I just need to learn how to make it stick to the floor when climbing down steps, as well as how to smooth the camera.
This method actually has a couple of upsides: it's simple (I think), and it prevents climbing on wall baseboards, and things of that nature. If I had a dollar for every time I had to create clip brushes in maps I made to prevent players from inadvertently climbing onto such things...
Quality content. Thank you!
YOU ARE A SAINT
Hey this tutorial has been exactly what i have been looking for thank you sir, i just have a question. Im porting this to 2D and when you set the expected motion variable to multiply delta by x and z, you say this is a 'forward' motion but I thought that the Z axis is the one which controls back and forth movement and the X is for left or right, can anyone help clarify? I appreciate it
Y is up, so i multiply by Vector3(1,0,1) which will set/multiply Y by 0. and leave X and Z the same. just interested in the horizontal move direction, yes as you said, that is X and Z. if this was in 2D, then you could do something like *Vector2(1,0) as you are only interested in horizontal movement, towards the stairs. but horizontal in 2D is only X as there is no Z dimension. you may have to get a bit creative in adapting it but the general concept is to simulate where the player would be, whichever way they are stepping, towards a stair for example, and then shoot a shape cast/body test motion down from slightly above to see if there is some stair there. if it hits and it is not too high of a jump, then you can let them step up.
Thank you for the reply! This helped me get on the right track as I barely had to change any code for correct function. I thought it wasn't working because of that direction variable but it was simply some values and checks which had to be switched around to negative for the y axis lol, I'm still very much a novice at this so thank you again.
Amazing tutorial! I encountered an issue where, for some reason, my camera smoothing node's x and z values were being changed. My manually resetting them via code, seems to have fixed the issue.
Thank you so so so much
love it!
Thank you :)!
Hi this method for handling stairs is really good, thank you for the tutorial!
I'm having one issue though. When my controller is moving against a wall and then slides towards steps it should be able to climb over it gets stuck and only updates the position of the character up the stairs when I stop moving. Any idea on how this could be fixed?
Your solution is really clever and works great, though I had a couple of issues;
If your movement speed is too slow it is not able to snap up the stairs and starts jittering up and down. I think this is because the translation distance is not sufficient enough at such a small velocity and the capsule simply slides back down, at least for my capsule size (radius of 0.2m). Is there a way to add a minimum velocity clamp to the expected_move_motion function?
The other issue i encountered was the camera smooth would have it's position moved on the z and x axis's when going down the stairs. Adding move toward code similar to the y axis solved this, but I was wondering if you or anyone else had this issue?
for the first part, you might try using a box shape instead of a capsule. i was thinking about switching my character controller to use a box instead, because of this issue where you can kind of be half on the floor sliding off it. if when walking up the stairs the character stops you can get caught slowly sliding down an edge like this and not technically be 'on floor'.
for the camera smooth, im not sure what you mean. i have mine set up so it only ever drifts it along the y axis. this makes sense to me because the horizontal speed is constant going up/down stairs as it is moving on floor. so just always move with character xz. also less glitchy with headbob that way from some testing i noticed.
@@MajikayoGames Thanks for the reply, what I ended up doing was removing the camera smoothing all together an instead interpolate my characters position between the steps instead. multiplying the interpolation speed by the step height and move speed also helped. Applying this technique to the snap down too. And of course switching to a box collider too :)
@@DEATHTRUTH mind if i ask what your interpolation looks like as code
@@Creeperassasin-nc5wk global_position.y = move_toward(global_position.y, step_pos_with_clearance.origin.y,0.015 * move_speed)
@@DEATHTRUTH thanks ill have to try it out later
i was using your tutorial to help with the stairs. i saw the _physics_proccess function and from fear that my code was missing something important i got into writing it down. Well my stupid but realized that this function is the exact same as the one i already have. Always preread before typing it down ig
Thanks mate! it perfectly work :3
I'm confused, it works, but I get stuck in place a lot. Sometimes I can't get out and have to restart the game.
This is an incredible and exceptionally well-explained solution! Thank you so very much, MajikayoGames. I'm ecstatic to have completed this great tutorial and I can't wait to see what else you've got and what's coming next.
Appreciate your comment :D glad you enjoyed!
This tutorial is very well made, however I am having trouble getting the going up the stairs check to work, so the player doesn't start going up the stairs. The down check works perfectly, but the going up check is causing issues for me. I followed your video exactly and compared mine to the github version and I'm not sure what's happened to make mine not work. I could send you the script if you want, but its pretty much the same as yours as I am trying to get a base for the movement.
after running through diffchecker i think i changed a down_check_result.get_position() to a down_check_result.get_collision_point()
great tutorial, works great now!
hi, im having an isue with the camara smoothing where, the higher up on the node tree i assighn the smoothing too when going down steps the more the camara sinks into the floor, and the lower on the node tree the higher the camra floats into the sky, all of the postions of these nodes are 0, 0, 0.
It's hard to say without looking at your code, but another person had a very similar problem, the solution ended up being the node structure and position. The head original position should be moved, and the rest stay at 0,0,0. If you have double checked your code and it's just like mine, i would think it's a similar thing. Are you sure the nodes are exactly the same as mine?
@@MajikayoGames it's not quite the same I have the character body witch is at 0,0,0. Then a body node also centered then a heads node that is moved up, and then a head 1 node that is centered and then the Camara node. The one I am smoothing is the head 1 node. One more thing to note is that the camera is not only drifting vertically but also horizontal. For now I just got rid of the camera smoothing and I plan to lerp the velocity down the stairs
@@zeepnely5678 Gotcha if you have your own setup, it may need some different code. This method is designed to be used with the exact same node and positions setup i have.
@@MajikayoGames alright, thanks for thinking about it!
thank you mate 🙏
Thanks for sharing!
An extra version that only contains the important code would be helpful. This way you would have to remove the noclip code etc. in a cumbersome way
When I press jump after going up or down stairs gravity is no longer being applied and I just float instead, how do I fix this :(?
Can't think of why this would happen. Do you mean you fly up in the air? Check my pinned comment, it may be due to y velocity accumulating when sticking to stairs. Just make sure you are not calling snap up stairs if y velocity is positive
@MajikayoGames Thx for the quick response! I don't get flung upwards, it's if I press jump I go up and don't come back down, I just float 😭 it only happens after going up or down stairs, the jumping works before then
@@porkyorcy1715 i cannot imagine why that's happening. if you want to pastebin your character script i could take a look.
@MajikayoGames idk if youtube lets me post links in comments, i sent u it on twitter 😈🙏
does this only work for players? can it work on an npc (nav agent) controlled?
Interesting question, right now I'm focusing on just doing a player script, but just as CSS has bots which will move by the same laws of physics & rules as the normal players, we could adapt this to be used for a bot script. For that, we would basically just simulate the player input. We might have to abstract the input layer a bit more, so the bot can essentially send fake inputs, depending on some navigational AI. I think the movement wouldn't be that hard, as we already have wish_dir variables which are just set to input. Instead of keyboard input, we would just look to the nav agent's instructions for the wished move direction. I'll write this down as an idea for a future tutorial as this could be pretty interesting I think. Thanks :)
Oh also, I realized you probably mean allowing bots to walk down stairs specifically. I haven't looked into that exactly, I would have to look into how navmesh works. If using godot's built in version, it would probably take some fine tuning, but I would think you would bake the nav mesh with the agent_max_climb set to the same height/slightly great than the max step height of your player. And it might take some tuning but I'm guessing something like above would work.
@@MajikayoGames yes, I'm trying a solution like yours and using the NPC's velocity as the direction, but no luck yet maybe I'm doing something wrong
@@MajikayoGames Yeah been having quite some difficulty figuring out all the navregion properties to create the perfect navmesh that can handle stairs (with non ramp collision) and and holes like doors and such. I think if you made a tutorial for it would be a fun (and maybe somewhat frustating xD) challenge and it would definitely be the only one on YT.
@@mrjshzk added it to my list of tutorial ideas :) i do like doing unique videos as they seem to get the most views. No competition i guess if im the only one making a video on a particular topic. I would probably be doing it a bit later in the series as i have a lot more tutorials to get through though
having a ceiling or something above the stairs prevents the player from stepping up, i cant figure out the fix
i got it
Very Geat tutorial. I works very good for me. Also, I have noticed when I try to walk up the stairs while im sided by two walls and face to the wall slightly i will stop moving. If I face staight i will work but being some angles off it will not. Do you know why this is happening and how I could fix it? If you dont no problem. And thank you for the tutorial it realy helped me.
Its because the code spawns the raycast basically at the spot where you would collide if you walk ahead at a higher level to calculate the step height. In your case you collide with the walls before the stairs - spawning the raycast in there and not allowing you to go further because the step height is at its limit. Got the same problem no idea on how to solve it though XD.
@@endlux3094 I see. So based on that I will try and find a way to fix that. If I do, I will inform you. Thanks for the answer. 🤝
@@sabertooth9137 I played around a bit and i think i might have something that works now. It still isnt that great if you walk in a large angle towards a wall (as in 45 degrees for example) but at least its something. Try it if you want - its basically just making more test moves at angles if the collision happens at an unexpected height
if (self.test_move(step_pos_with_clearance, Vector3(0,-MAX_STEP_HEIGHT*1.3,0), down_check_result)
and (down_check_result.get_collider().is_class("StaticBody3D") or down_check_result.get_collider().is_class("CSGShape3D"))):
if down_check_result.get_position().y > step_pos_with_clearance.origin.y:
var raycast_left_pos = self.global_transform.translated(expected_move_motion.rotated(Vector3(0, 1, 0), deg_to_rad(20)) + Vector3(0, MAX_STEP_HEIGHT * 1.3, 0))
self.test_move(raycast_left_pos, Vector3(0,-MAX_STEP_HEIGHT*1.3,0), down_check_result)
if down_check_result.get_position().y > step_pos_with_clearance.origin.y:
var raycast_right_pos = self.global_transform.translated(expected_move_motion.rotated(Vector3(0, 1, 0), deg_to_rad(-20)) + Vector3(0, MAX_STEP_HEIGHT * 1.3, 0))
self.test_move(raycast_right_pos, Vector3(0,-MAX_STEP_HEIGHT*1.3,0), down_check_result)
var step_height = ((step_pos_with_clearance.origin + down_check_result.get_travel()) - self.global_position).y
(gotta change the clearance amount if you want to have Max_step x 2)
💪🏼
Thank you
Nice code.
nice job. I use shapecast for step checking. And I give up on using Physics test. Positioning of shapecast or raycast is important if you want to add crouch