Using: Unity 3D5
So you want to add some stairs to your game? Great! Adding stairs in level design adds more vertical variety to your levels. Or perhaps your game is based on stairs (Stair Climbing Simulator 2018?).
In this tutorial I’ll show you how to implement stair climbing from scratch in Unity3D if you’re using a
Rigidbody as your player. Before we get to coding, you should consider your (much easier / less work) alternatives:
- Use a
CharacterController. It already has some support for this, but can’t have physics applied willy nilly, nor is it as customizable as a
Rigidbodywith multiple colliders.
- Use a
Rigidbody. If you get the player going fast enough they can just ram right over the stairs.
- Use ramps or stairs with invisible ramps over the steps. They work just as well and even provide a smooth transition surface. Doesn’t work for cases of dynamic/physics content or player generated content.
If you’ve looked into these and you still need stairs, let’s dive in.
Scope and Requirements
This tutorial uses Unity3D and C# but the concepts should be the same (except for the Unity specific quirks I mention). The stair stepping style is based off of the behavior found in the Source Engine.
You should also have a working
MonoBehaviour script for simple player controls that uses a
It should be able to move at a minimum. If you don’t,
RigidbodyFPSWalker is a decent start
The stair stepping can be tweaked in numerous ways. For now, we will define only two parameters explicitly that will be used later in the tutorial.
A quick look at ContactPoints
The physics engine in Unity3D, PhysX, generates collision events
OnCollisionStay, …). These collision events return a
Collision object with gobs of information.
A nifty little property on this object is the
.contacts member which gives a list of all of the points of contact in a collision (well, usually all of them, sometimes it doesn’t but only with complex collision
MeshColliders hitting each other).
ContactPoints come with a position, a normal, and collider information.
For visualization, here’s a collision between my player (a green
BoxCollider), a surface, and the resulting ContactPoints. The ContactPoints are visualized as blue lines.
Getting the ContactPoints
We need all the ContactPoints every physics frame. To capture them we save all ContactPoints generated by both
We need to loop through all the
ContactPoints and then do the stair step.
It is best to do this in
FixedUpdate as we’re working with physics data which is only generated every physics frame.
Detecting ground and a stair
Now that we have all the
ContactPoints for the player we need to look through them for some specifics
For the rest of the tutorial this will be the example situation we’ll be looking at
Detecting the ground
Detecting the ground must be done before looking for stair steps. We can say that ground is any
ContactPoint with a Y (up) normal component of greater than 0.0001 meaning that it has some sort of
upward direction to it.
From this function we are able to determine if the player is grounded as well as at what Y value the player is grounded.
Detecting a stair
Detecting a stair is a much more intensive process that requires a lot of math.
FindStep does very similar things to
First, we don’t care about any stairs if the player is not moving.
Second, the actual checks are done in
ResolveStepUp but the process is the same, check every
Now we start building
ContactPoints to be considered a stair, they have to remotely look like a stair. When the player hits the stairs, it’s like hitting a really short wall and it will generate
ContactPoints with really low Y (up) directional components for their normals.
So, for each
ContactPoint, we only used the ones with low Y normal values
Considering this check says nothing about the height at which this
ContactPoint occured, it should filter out all the ones that are too high for the player to step up to
We’ve now gathered quite a bit of data.
Determining where to step up
We’ve detected a stair, this is cool, but we don’t know how to get up it.
How to step up
We hit something, figured out it was a stair, and even got the position to where we’re going to step up. We did this all in the beginning of
FixedUpdate and we will now check at the end whether to step up or not.
NOTE: You’ll need the last physics frame velocity in order to make the step feel smooth as the player is stopped by the time we read the
ContactPoint where they hit the wall.
Combining everything above, here’s the full code put together. You will have to modify this to play nicely with your version of
RigidBodyFPSWalker or the like.
Keep in mind the only real restriction that we placed on the player was that they can only step up things with a horizontal normal and things that are under a specific height. There are a few corner cases with this method including
- Making sure that if the player creeps back down a step, it doesn’t try to step them back up.
- Player is too wide to step up into the given area.
- When a collider is deleted in between physics frames (null checks needed on colliders in
but these I’ll leave these up to you to implement. They build off of the checks in