Menu
CoddyTech

The Course

Part of the Building Real Games section of Coddy's Unity journey. Lesson 48 of 56.

This chapter builds a 3D platformer. You run and jump across floating platforms, ride one that glides, touch checkpoints so a fall does not send you back to the start, collect gems counted on screen, cross the finish into the next level and try to beat your best time. The game is five scripts, in the project from the start: Player, MovingPlatform, Checkpoint, Gem and FinishLine. The last four are empty for now, and each lesson fills one in. The player is a CharacterController steered with the Input System's actions, and the camera is its child, so it follows without a script.

A CharacterController moves in two ways. Move(motion) moves it by a distance and adds nothing, so gravity, jumps and Time.deltaTime are the script's job, as in the Character Controller chapter. SimpleMove(speed) takes a speed in units per second, scales it by the frame's time itself and adds gravity; it ignores the y you pass, so a character moved with it falls off ledges but can never jump. This sheepdog in a herding game seen from above needs no jump, so SimpleMove and the Move action are its whole script:

using UnityEngine;
using UnityEngine.InputSystem;

public class Sheepdog : MonoBehaviour
{
    [SerializeField] private float speed = 6f;
    private CharacterController controller;
    private InputAction moveAction;

    void Start()
    {
        controller = GetComponent<CharacterController>();
        moveAction = InputSystem.actions.FindAction("Move");
    }

    void Update()
    {
        Vector2 input = moveAction.ReadValue<Vector2>();
        controller.SimpleMove(new Vector3(input.x, 0f, input.y) * speed);
    }
}

The platformer's player has to jump, so it keeps its own vertical velocity and moves with Move, reading the Move and Jump actions instead of the Input class. Unity recommends one call to Move or SimpleMove per frame: the walk and the fall go into the same call, and isGrounded then describes that whole move.

challenge icon

Challenge

Medium

Start the platformer with the player. The Player script has speed (5), jumpHeight (1.5) and gravity (-9.81), the controller and a velocity for the fall. Find the Move and Jump actions once, in Start, and in Update:

  • Move walks the player at speed units per second: right and left along x, forward and back along z.
  • Gravity adds gravity * Time.deltaTime to velocity.y every frame. While the controller is grounded and velocity.y is below 0, set velocity.y to -2 first, so it stays pressed to the ground.
  • Each press of Jump, while grounded, sets velocity.y to Mathf.Sqrt(jumpHeight * -2f * gravity): a jump jumpHeight units high. Holding Jump jumps once, and there is no jumping in mid-air.
  • Call controller.Move once, with the walk and velocity together, times Time.deltaTime.

Press Play and jump across to the first platforms, then Check.

Try it yourself

using UnityEngine;
using UnityEngine.InputSystem;

public class Player : MonoBehaviour
{
    [SerializeField] private float speed = 5f;
    [SerializeField] private float jumpHeight = 1.5f;
    [SerializeField] private float gravity = -9.81f;

    private CharacterController controller;
    private Vector3 velocity;

    void Start()
    {
        controller = GetComponent<CharacterController>();
    }

    void Update()
    {
        // walk with the Move action, jump with the Jump action, fall with gravity
    }
}
quiz iconTest yourself

This lesson includes a short quiz. Start the lesson to answer it and track your progress.

All lessons in Building Real Games