Unity: CHARACTER CONTROLLER vs RIGIDBODY

Aug. 7, 2017
protect

When you’re creating a new project with Unity, one of the first things you have to do is code your avatar’s controller. It’s very important and you can’t rush it or your gamefeel will probably be bad. There are a lot of different things to do, ranging from the inputs acquisition to the movements and feedbacks. 
One of the first question I often ask myself is : “Should I use a Character Controller or a Rigidbody? ”.
Today, through the example of a simple moving, jumping and dashing avatar, we will explore the two approaches.

Here is a github of the complete project:
 https://github.com/valgoun/CharacterController

The Character Controller approach

Setup

Before anything let’s just setup the project and a basic test scene. As written in our 8 Essential Gamedev Tipswe must be organized. Create these folders:

 

 

 

 

 

 

Then create a very simple scene with a ground, a capsule (our Player) and a stair to play with. 
Adding some verticality with the stairs will allow us to experiment with a lot of different and important things when coding our character: The way it collides with objects, the gravity when falling from a distance, and also to test the jumping mechanic if we want one.

I also put a simple box as a child of our player so we can see its orientation when looking around).

I also put a simple box as a child of our player so we can see its orientation when looking around).

Keep your scene clean, use parents.

 

The Character Controller

The Character Controller is a component you can add to your player. Its function is to move the player according to the environment (the colliders).
It doesn’t respond nor uses physics in any way. 
On top of that, the Character Controller comes with a Capsule Collider. Before seeing how it works, I recommend you to take a look at the manual and the scripting API, it’s always a good thing to do.

For this example, I used the default parameters but feel free to play with them to understand how they work.

 

The core concept behind the Character Controller is that it provides basic collider responses without any physics. Basically, you will move your player like you would do with a Transform, but you can’t go through colliders. 
The main advantage of using this technique is the amount of control we’ll have on how your player behaves, but the downfall is that you’ll have to code practically everything.

The Character Controller includes 2 methods used to move the character: SimpleMove and Move.

SimpleMove takes the speed as parameter and will move the character accordingly. On top of that, the character will respond to gravity. That’s the only physic you’ll get with the Character Controller. The downside is that the Y axis velocity is ignored by this method.

Move requires a little bit more work but is less limited. It takes in parameters the absolute movement. Therefore, it’s framerate dependent and you have to implement gravity on your own.

Even if it’s the more complicated method, it’s the one I prefer because SimpleMove becomes very quickly limiting by the fact that you have no effect on the Y axis velocity.

 

Basic Movements

Let’s implement a very basic movement. For this, let’s create a new C# script named “Character” that we add to our Player/capsule. Then, we’ll need a public variable so we can tweak the speed directly from the editor and a private variable to store a reference to our Character Controller.
(don’t forget to get the Character Controller in the Start method, see code below)

In the Update function, we get the Inputs, that we then store into a Vector3. After, we call the Move method from our CharacterController passing it the Input vector multiplied by the speed and the DeltaTime to be framerate independent and “voilà”, we have our basic movements:


public class Character : MonoBehaviour
{ 
private CharacterController _controller;

void Start()
    {
        _controller = GetComponent<CharacterController>();
    }
    
void Update()
    {
    Vector3 move = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
    _controller.Move(move * Time.deltaTime * Speed);
    }
    
}

 

Our character moves but doesn’t steer according to its movement. It’s easy to change the forward vector of the transform to be the movement vector:


 Vector3 move = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
    _controller.Move(move * Time.deltaTime * Speed);
        if (move != Vector3.zero)
            transform.forward = move;

 

Gravity

Let’s add gravity. For that, we’ll need a… gravity variable (or you can use the global gravity with Physics.gravity.y) and private variable to store the velocity of the character. 
Then, we just have to add the gravity to our player’s velocity at each update and to apply the velocity with the Move method:



 _velocity.y += Gravity * Time.deltaTime;
 _controller.Move(_velocity * Time.deltaTime);

If you try, you will probably feel the gravity as a bit weird. It’s because even when the player is grounded, the velocity is still increasing following the gravity.

To resolve this, we can reset the y velocity to 0 when the player is grounded. 
The CharacterController already has a variable to know if the character is grounded but I found it buggy and I tend to determine myself if the player is grounded. I Like to use the CheckSphere method from the Physics Class. It returns true if any colliders intersect the sphere defined by the parameters. I like to use an empty gameObject child of my player as center of the sphere and then I use a variable for the radius and the layer. This way I can control in editor the way I define the grounded status of my character. (If this part seems hard to understand, take a look at my project and recreate it on yours).


_isGrounded = Physics.CheckSphere(_groundChecker.position, GroundDistance, Ground, QueryTriggerInteraction.Ignore);
        if (_isGrounded && _velocity.y < 0)
            _velocity.y = 0f;

Here, _isGrounded is a bool variable created in the class, _groundChecker is a reference to the child of the player (the center of the sphere), GroundDistance is the radius of the sphere and Ground is the layer where ground objects are.

 

Jump

Adding a jump is pretty easy. When the jump button is pressed and the player grounded, we change the y velocity. To know which value we choose to set our velocity we can use this formula:

“velocity = JumpHeight * -2 * Gravity”


if (Input.GetButtonDown("Jump") && _isGrounded)
    _velocity.y += Mathf.Sqrt(JumpHeight * -2f * Gravity);

Here I chose to use some fancy math so I have a more convenient variable to control my jump (JumpHeight). Other would have chosen to use a direct variable (JumpForce) to control the jump : easier to code, trickier to control.


if (Input.GetButtonDown("Jump") && _isGrounded)
    _velocity.y += JumpForce;

 

Dash and Drag

One last example o

JikGuard.com, a high-tech security service provider focusing on game protection and anti-cheat, is committed to helping game companies solve the problem of cheats and hacks, and providing deeply integrated encryption protection solutions for games.

Read More>>