I have now uploaded the script to GitHub link in the description. This script also contains the enhancement suggested by Moonbuffalo which multiplies the smoothStep amount by Time.DeltaTime, this gives a much smoother and cleaner looking walk with far less jump to it. This also means that the smoothStep amount has been increased to a much higher value than before, in this case 2.
@@ahmedkarim5894 you should always use Time.deltaTime. It will know if you're in the update or fixedUpdate function and give you correct delta time accordingly. Time.fixedDeltaTime is the target delta time you want it to be, i.e. you write to it.
Nice work on the script and the video! But I do have a question: Why do you modifiy the rb position with -= and then -stepSmooth? Wouldn't += easier/better? Or is there any specific reason to use - -?
Thank you for the tips, this is the only video that shows exactly how to deal with slope on physics without tweaking colider. There is one thing, that instead of cast the ray on the direction of world space, casting ray on the direction of your movement inputs will save you from doing another ray cast check.
In the article, fixed values (0.1 and 0.2) are used for the detection distance, which will cause stuttering in some cases. To fix this, I changed it to a value proportional to the object's velocity. This optimizes the feel to a certain extent.
The way you used the raycast approach for detecting stairs is very clever, easy to visualize and understand how it works, doesn't require complex math. Thank you so much for the tutorial, have a good day sir
@@MEMUNDOLOL This is a player controlled unit, no one would implement the same type of logic for Ai-based movement. And if you talk multiplayer, the calculation would be done client side, once per player then sending new position to server. All your examples are false comparisons. Ai based movement usualys follows a predefined path, defining that path is a completly different discussion. If you are talking about actually optimizing things you should know that few games run their AI logic every frame, its simply not needed to have that type of precision.
Wanted to say thanks for the updated step detection feature. Another thing I added that seems to help is adding zero friction to the player's capsule collider. However, if there is any friction like max friction on steps it wont do anything. Also with zero friction physics material added, I found that in order to climate some of the jittering that setting stepSmooth = 0.02f works best rather than stepSmooth = 2f. I also added range settings in case I may need them to adjust things later like this: [SerializeField][Range(0, 5)] private float maxStepHeight = 0.3f; [SerializeField][Range(0, 5)] private float stepSmooth = 0.02f; I would also like to see perhaps in the near future a video adding kinematics so that foot placement looks more natural without having to mess wit the animator or animation. That would be awesome. Thanks again, as I said for the updated script. I was able to adapt it much easier than I thought I would be able to.
Great tutorial! I liked how you showed what the viewer can expect to have by the end of the video. That really helped me figure out if your solution is what I was looking for. It is and I'm looking forward to trying it out. A suggestion, do more Unity videos. Good luck and take care!
New idea, try to make walking on stairs facing all directions, for example while the player is walking backwards. Because the implementation you made is only for when facing the stairs. Nice video btw and thank you!
Hey, I've also been working on a character controller. I used a method where the collider flies above the ground, but your solution seems much better =) Thank you very much.
Nice! I think it would be better if you multiplied your smoothstep by time.deltatime. this way you can think of your smoothstep with units that are a rate (meters per second). With out it you're making the time it takes to climb stairs frame dependent (meters per frame).
That is a very good point that completely slipped my mind, thanks for your comment, I am going to pin this so that others can see it as I highly recommend everyone does this
The explanation given for the upper raycast being longer than the lower one was that this will allow you to climb slopes. I'm confused by this. We are checking if we hit nothing, right? So it shouldn't matter for slopes if the upper ray is longer or the same, no? To me it seems like making the upper ray longer means you /won't/ be able to climb slight slopes, whereas if you make it equal, you can step up? Or maybe, is the upper raycast longer to disallow stepping/climbing tall walls that are slightly slanted away? If the ray is equal, you will step up since the upper one won't detect anything, but if the upper ray is longer, you won't be able to climb it. Not sure if I'm understanding this correctly.
Very glad to have found this solution! However, I've noticed when my character is right up against a change in elevation (be it a bump or a step), he doesn't move and step at all. I have to either jump and move forward, or back up and gain momentum.
Yeah it’s the same for me, i either have to go at a certain speed. And i also have a problem with stairs as my character climb them really slowly and he also slide from them.
I don't know if by now you fixed this problem or not, but i'm going to leave this here: i got the same problem you had and to solve it, i made the float value of the raycast rays highter and multiply the -stepSmooth by Time.deltaTime
It's been a long time since this comment, but I figured another solution. Instead of changing th "transform.position" value every frame, just make the "rigidBody.velocity" a fixed value on the Y axis, that way you don't get jerky movement if you're not going fast enough. private void Stepping() { Ray rayLower = new Ray(transform.position + Vector3.up * 0.05f, transform.forward); Ray rayUpper = new Ray(transform.position + Vector3.up * (human.height / 3), transform.forward); RaycastHit hitLower, hitUpper; float stepSmooth = 70f; if (Physics.Raycast(rayLower, out hitLower, human.width + 0.05f)) { if (!Physics.Raycast(rayUpper, out hitUpper, human.width + 0.2f)) { rigB.velocity = new Vector3(0, Time.fixedDeltaTime * stepSmooth, 0); } } } Also, "Time.fixedDeltaTime" ensures that the change will always be the same, independent of the frame rate. If your game's physics are running at 50 frames, then FixedDeltaTime would be 0.02, and the resulting Y velocity would be 1.4m/s, meaning you should go up quite quickly, but not too quick. You can always change this value to something more comfortable. Remember, for anything in FixedUpdate, use FixedDeltaTime.
Thanks for this great video! I wonder if making the character a nav mesh agent might solve the problem of climbing stairs without any custom scripts. I've seen it work for NPCs, but I am not sure if it would work if you make a character with a Rigid Body a nav mesh agent. Just a thought.
You could easily just set rigidbody.velocity.normalized as the direction of raycast. Just nullify the y value of velocity and you are good. This also makes sure that if you have some inertia, step offset will also work
@@spencershomaker8980 Sorry for late reply. Not sure how I would enter that properly in the code line. Also been ill for a while so again sorry for the late reply.
For those who use slope system, the controller can be buggy. that's why it's good to use this little system here that checks if the angle of the lower radius is greater than or equal to 90 to apply the step climb. float lowerNormalAngle = Vector3.Angle(transform.up, hitLower.normal); if (hitLower.collider != null && lowerNormalAngle >= 90) { if (hitUpper.collider == null) { Rigidbody.position -= new Vector3(0f, -Preset.stepSmooth, 0f); } }
Have you also tried also sending a ray downwards for more percision in case there are any wierd gaps between the walls so that the player wouldn't wierdly jump around? Havent tried it, but it made sense in my mind lol
i copied it directly and i dont have any errors...but its not working. It just still wont let me go up steps. The step height is high enough and the stepRay upper and lowers are in place both on the character and in the public script
Im not sure if I’ve done it wrong but I put the code in the player movement script and it didn’t work. I tried to also make it its own script I changed different values and even tried copy pasting it straight from your website. Also my character is a capsule shape
or create a cylinder that act as a trigger, check height and direction player is moving, if direction player is moving like diagonal is high enough to step in then set position. that should solve raycast not triggering like you want it it. Other way I did it was create a cone model, set the cone to 45 deg, height to how high I want my character can step up, add an empty child to my character, add rigidbody component, add mesh collider with my cone model as mesh, set convex, set the proper size, move the characters capsule collider a bit higher, and I can now move up steps without adding a single line of code. This is cause your character to slowly slide when their on the edge so adding physics properties or experimenting your own shape it allow the base of your character to slide up step. This will save you time figuring out different orientation and direction your character is going.
How would you do this in a 2D project? I'm having trouble getting this line of code to work: rigidBody.position -= new Vector3(0f, -stepSmooth * Time.deltaTime, 0f);
@@RealNekoGamer I've tried that, and many other things. The "Vector2" gives an error because of the "-=". and to get the Vector3 to work I tried, instead of rigidbody.position, transform.position and that seems to do the trick
super useful tutorial! But what about when you stop moving on a set of stairs? My player bounces up and down on the spot and im not sure what to do for a work-around
Pretty cool. There's just one bug for me that started to come out of nowhere all of a sudden which started to drive me crazy. I discovered that it started working again if you disable the component and then enable it. Why this works or happens is a mystery to me...
Thanks for the tutorial... Shouldn't rigidbody position be in the else statement of the second if? Because that what I had to do to make it work. I. E. If the upper Ray hits something then don't step-up, else { step-up / rigidbody. Position-=}.....
The second if statement that I use is a not if, I am inverting the condition with the "!" so the statement is actually checking if the condition is "not" true, this removes the need for an else statement
Looks like I'm not the only Welshman (I'm guessing by the accent) who's struggled with stairs! I'll have to give this solution a try, as my own solution became very convoluted, but the in-game result looks very similar to yours. I was trying to create a sort of "fake ramp movement" where I'd calculate the angle/direction from where the character is standing, to the point where they would be stepping up to, and then altered the players movement direction according to that. It involves a bazillion raycasts and lots of fudged maths, and I'm sure is massively inefficient. Maybe this simpler approach is what I need!
I have a slightly updated script linked in the description that should be completely stand alone that can just be added to your character, if you are still having issues then it could be something wrong with the raycasts, to debug this I would have the raycasts be drawn both when they do AND don't hit anything, then when you run around you should be able to see and make sure that they are casting out in the direction and distance that you expect them too
@@dawnscrowgames4485 yo bro first of all i just want to say you are awesome and bro thanks you your tut helped me to get my head around rigid body... Enjoy take care and yeah thank you again
Yes, you could replicate this method having raycasts casting out the back of the character as well as the front meaning you would have 6 angles of cover rather than the 3 demonstrated in this video. Some ways of optimizing this could be to only activate the raycasts in the direction that you are trying to move so only when you are walking backwards will you cast our the back and only when you are walking forward will you cast out the front.
@@brennenrocks The character in the video is using a simple capsule collider, this method isn't affected by the collider so shouldn't be the problem here.
Yeah no problem buddy, I separated out the the parts from the tutorial into it's own script and have now linked to it on GitHub in the description. I will be sure to do this by default with any future tutorials I make. Thanks.
@@dawnscrowgames4485 Thanks for the script. But it also depends on your move and gravity handle implementation. I've already adopted it for my case. But it hadn't worked for me before, because I don't handle gravity by myself and useGravity is enabled for my Player object. Also I push player by addForce function. So it was little bit confusing how to force it to work in my case, without your implementations of move and gravity. It still interesting for me to see your full script) Sorry for my bad English.
The script added to the GitHub is a completely self contained script which has no dependency on any move/gravity, This script will work on any Rigidbody you add it to even with the Rigidbody default gravity turned on. The script raycasts into object and then moves the Rigidbody position up until the raycasts are no longer colliding with anything
@@dawnscrowgames4485 Anyway it will be great if you make tutorials about another parts of your controller, because I still can't achive so smoothly and correctly working character controller as yours. Thanks for your previous answers.
No, you're an idiot for commenting this because the raycast was hitting the player. Fixed this by adding a layer mask to the script so it ignores the player layer
The stepRayUpper and stepRayLower are just empty game objects that we have created so that we can position them where we want and have a visual representation in relation to the model, then are then simply taking the position of those empty game objects to be used in the code rather than setting direct position values. This makes it much easier to adjust the heights without needing to trial and error some random positional values in the code.
@@dawnscrowgames4485 do i have to do other things ? i copied the script named it correctly , created the ''stepRay" objects, but it seems it does nothing .