While Unity’s default FPS Character Controller is very good, it does have a few shortcomings, such as being unable to be affected by rigidbody physics. Granted, most of the time this is a good thing, as making the player behave too realistically in terms of physics can make it quite hard to control. For example, players expect to come to complete stop when they release the move keys, which is not very realistic. There should be a period of deceleration where the player slows down after the move keys have been released. But if you actually implemented this in the game, it would just need to very confusing and non-intuitive controls.
However, there are situations where you want the character controller to be affected by external rigidbodies (such as being pushed away by a moving platform), or be able to change the up direction of your character to something other than the y-axis (for example if you want your character to rotate and walk up a wall). In these cases then, you need to take a rigidbody object, and then roll a character controller for it, so that you get all the behaviors you would normally get with rigidbody physics.
Fortunately, on the Unify Community Wiki page, there’s a very handy rigidbody controller script. While it’s pretty good for the most part, one major feature that it is lacking is the ability to set a number for degree of the incline that the character can climb up, and the height of stair steps that the character can scale. Instead, when climbing stairs, you are basically applying a force on the rigidbody character against the staircase, and pushing the character up this way. This creates two problems:
- Ascending and descending the stairs can be very bumpy, since going up each step is basically a collision event, and going down each step is basically a very short fall.
- The height of each step is very limited, and you need a large depth-to-height ratio for each step. While this may not be a problem for everyone, it does affect the aesthetics and architecture design. For example, in my game, I want each step to have a 1:1 ratio of depth to height, so that the stairs are basically at a 45 degree incline. However, in order for the player to climb this, I need to make the steps very small, at which point it no longer resembles stairs, but a slope with ridges.
After ignoring this problem for months, I finally came up with a solution after a conversation with a friend. I call the solution “Ghost Stairs”.
Basically, the solution consists of creating two sets of stairs, overlapping one another. The first set, let’s call it the “Real Stairs”, consist of the steps as you would like them to appear to the player in the game, shown in the picture below.
The second set of stairs, the “Ghost Stairs”, consist of steps with much smaller height increments, basically filling in the gap of the real stairs, and smoothing out the incline. In overlaps the real stairs in the same position. In the picture below, the ghost stairs are shown in green (the weird looking texture on the side of the staircase is due to the overlapping of the two meshes).
So there are two separate meshes on the staircase. Then, when the staircase is brought into Unity, I added mesh colliders to both sets of stairs, but disable the renderer of the ghost stairs, so that the player can collide with it, but it can’t be seen. In the picture below, you can see the mesh collider outline of the ghost stairs.
This set up really fixes the bumpiness when going up the stairs. Going down the stairs was not quite as smooth, but by reducing the mass of the player rigidbody a bit, so that the player kind of floats down while descending, helped to fix that.
However, one problem that ghost stairs produces is that now, if you place a game object, like a box, on top of the stairs, it will collide with the ghost stairs and appear to be floating in mid-air. This is fixed by using Unity’s Layer Collision Matrix (found under “Physic” in “Project Settings”). Basically, I put any movable objects such as boxes in a layer called “Movable”, and then put the ghost stairs in another layer called “Ghost”, and then uncheck the box in the collision matrix to ensure that these two layers don’t collide with one another.
So finally, this is what it looks like in the game (from the scene view) when the player and a box is on the stairs:
You can see that the player is resting on top of the ghost stairs, when the box is resting on the real stairs.
Anyway, I’m pretty happy to have solved a problem that had plaguing me for quite some time, and just wanted to share the solution. Hopefully you’ve found the information here to be somewhat helpful.