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
MediumStart 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
speedunits per second: right and left along x, forward and back along z. - Gravity adds
gravity * Time.deltaTimetovelocity.yevery frame. While the controller is grounded andvelocity.yis below 0, setvelocity.yto -2 first, so it stays pressed to the ground. - Each press of Jump, while grounded, sets
velocity.ytoMathf.Sqrt(jumpHeight * -2f * gravity): a jumpjumpHeightunits high. Holding Jump jumps once, and there is no jumping in mid-air. - Call
controller.Moveonce, with the walk andvelocitytogether, timesTime.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
}
}
This lesson includes a short quiz. Start the lesson to answer it and track your progress.
All lessons in Building Real Games
2Buttons and Screens
Buttons and onClickLambdasWiring in the InspectorPanels On and OffHealth BarsRecap: Upgrade Shop5Saving with PlayerPrefs
Save a NumberLoad with a DefaultHigh ScoreSave SettingsRecap: Coins in the Bank3The Game Manager
One Script Runs the GameThe SingletonGame StatesSwitching on the StateRecap: Round Manager6Project: Endless Runner
Three LanesObstacles Ahead9The New Input System
Two Input SystemsKeyboard and MousePressed This FrameInput ActionsRecap: Input Swap