
Your character can move. Great! But what happens when it reaches a wall? What about gravity, slopes, or jumping?
If you're building a 3D Unity game, simply changing the player's Transform isn't always enough. For a more reliable character controller, Unity provides the CharacterController component.
In this beginner-friendly tutorial, we'll use CharacterController to create a simple player controller with movement, collision detection, gravity, and jumping.
What Is CharacterController in Unity?
CharacterController is a Unity component designed for controlling characters without using a Rigidbody for their basic movement.
It can help your player:
- Move around the environment
- Collide with walls and other objects
- Stay on the ground
- Handle slopes and steps
- Move without passing through colliders
It's commonly used for first-person and third-person player controllers.
Note: CharacterController is not a physics Rigidbody. If you need your player to behave like a physics object, a Rigidbody may be a better choice.
Step 1: Create a Player
For testing, let's create a simple Capsule.
In Unity:
Hierarchy → Right-click → 3D Object → Capsule
Rename it:
Player
Set its position to:
X = 0
Y = 1
Z = 0
You can later replace the Capsule with your actual character model.
Step 2: Add CharacterController
Select your Player object.
In the Inspector, select:
Add Component → Character Controller
Unity will add a CharacterController component.
You should see properties such as:
- Center
- Radius
- Height
- Slope Limit
- Step Offset
For a Capsule player, Unity's default values are usually a good starting point.
Step 3: Create the Player Movement Script
Create a new C# script:
PlayerController
Open it and add:
using UnityEngine;
public class PlayerController : MonoBehaviour
{
public float moveSpeed = 5f;
public float gravity = -9.81f;
public float jumpHeight = 1.5f;
private CharacterController controller;
private Vector3 velocity;
void Start()
{
controller = GetComponent<CharacterController>();
}
void Update()
{
float horizontal = Input.GetAxisRaw("Horizontal");
float vertical = Input.GetAxisRaw("Vertical");
Vector3 direction = new Vector3(horizontal, 0f, vertical);
direction = direction.normalized;
controller.Move(direction * moveSpeed * Time.deltaTime);
if (controller.isGrounded && velocity.y < 0)
{
velocity.y = -2f;
}
if (Input.GetButtonDown("Jump") && controller.isGrounded)
{
velocity.y = Mathf.Sqrt(jumpHeight * -2f * gravity);
}
velocity.y += gravity * Time.deltaTime;
controller.Move(velocity * Time.deltaTime);
}
}
Attach the script to your Player GameObject.
Step 4: Test Player Movement
Press Play.
You can now use:
- W / Up Arrow → Move forward
- S / Down Arrow → Move backward
- A / Left Arrow → Move left
- D / Right Arrow → Move right
- Space → Jump
The CharacterController will handle collisions with objects that have colliders.
How Does CharacterController.Move() Work?
The main movement happens here:
controller.Move(direction * moveSpeed * Time.deltaTime);
Instead of directly changing the player's transform, we're asking the CharacterController to move the character.
This is important because the controller can detect collisions while moving.
For example, if your player walks toward a wall with a Collider, the CharacterController won't simply move through it.
Why Use .normalized?
We create our movement direction with:
Vector3 direction = new Vector3(horizontal, 0f, vertical);
direction = direction.normalized;
Without normalization, moving diagonally could make the player move faster than moving in one direction.
.normalized keeps the direction's length consistent.
Adding Gravity
One common beginner mistake is assuming that CharacterController automatically applies gravity.
It doesn't.
That's why we create:
private Vector3 velocity;
Then apply gravity:
velocity.y += gravity * Time.deltaTime;
Finally, we move the controller vertically:
controller.Move(velocity * Time.deltaTime);
This gives the character natural downward movement.
Keeping the Player on the Ground
We use:
if (controller.isGrounded && velocity.y < 0)
{
velocity.y = -2f;
}
controller.isGrounded tells us whether the character is touching the ground.
Setting a small negative value instead of 0 helps keep the controller properly grounded.
Adding Jumping
The jump happens here:
if (Input.GetButtonDown("Jump") && controller.isGrounded)
{
velocity.y = Mathf.Sqrt(jumpHeight * -2f * gravity);
}
The important part is the controller.isGrounded check.
It prevents the player from continuously jumping while already in the air.
You can make the jump higher by increasing:
jumpHeight = 1.5f;
For example:
1.0 → Small jump
1.5 → Normal jump
3.0 → High jump
Make Sure Your Floor Has a Collider
Your CharacterController needs something to collide with.
For example, create a Plane:
Hierarchy → 3D Object → Plane
A Unity Plane already has a MeshCollider.
You can also use cubes as floors and walls. A Cube has a BoxCollider by default.
Your scene might look like:
Scene
├── Main Camera
├── Directional Light
├── Player
│ ├── CharacterController
│ └── PlayerController
├── Ground
│ └── Collider
└── Wall
└── Collider
CharacterController vs Rigidbody
Both approaches can be useful, but they solve slightly different problems.
| CharacterController | Rigidbody |
|---|---|
| Designed for character movement | Physics-based |
| Easy to control directly | Uses physics simulation |
| Great for FPS/TPS characters | Great for physics-driven characters |
| Handles character collisions | Handles forces and physics |
| Gravity must be coded | Gravity can come from physics |
For a traditional player-controlled character, CharacterController is a good starting point.
Common Beginner Problems
Player Falls Through the Floor
Make sure the floor has a Collider.
Player Doesn't Move
Check that:
-
PlayerControlleris attached. -
CharacterControlleris attached. - You're pressing the correct movement keys.
- The GameObject is active.
Player Can Jump in the Air
Make sure your jump code includes:
controller.isGrounded
Player Moves Too Fast
Lower:
moveSpeed = 5f;
Try 3f or 4f.
What Can You Add Next?
Once this basic controller works, you can expand it with:
- Sprinting
- Crouching
- Smooth character rotation
- First-person camera
- Third-person camera
- Animation transitions
- Footstep sounds
- Stamina
- Mobile joystick controls
- Slope handling
The important thing is to build these features one at a time.
Check here - Unity game development tutorials
Final Thoughts
A CharacterController gives you a solid starting point for building a 3D player in Unity. Instead of simply moving the Transform, you get a controller designed specifically for character movement and collision handling.
Start with basic movement, then add gravity and jumping. Once you understand how CharacterController.Move(), isGrounded, and velocity work together, you'll have a much better foundation for creating more advanced player controllers.
Did you use CharacterController or Rigidbody in your first Unity game? Share your experience in the comments!
Top comments (0)