Menu
CoddyTech

A State Machine

Part of the Game Architecture in Unity section of Coddy's Unity journey. Lesson 29 of 50.

The Beacon's SetState method would be the same in every object with states: a turret, an enemy, a door. That code can live in a class of its own, a state machine, which holds the current state and changes it. Each object makes one machine and calls it, instead of repeating the code:

public class StateMachine
{
    public IState Current { get; private set; }

    public void ChangeState(IState next)
    {
        Current?.Exit();
        Current = next;
        Current.Enter();
    }

    public void Tick()
    {
        Current?.Tick();
    }
}

public class Beacon : MonoBehaviour
{
    public Renderer lamp;
    private StateMachine machine = new StateMachine();
    private IState blink;
    private IState steady;

    void Start()
    {
        blink = new BlinkState(lamp);
        steady = new SteadyState();
        machine.ChangeState(steady);
    }

    void Update()
    {
        if (Keyboard.current.spaceKey.wasPressedThisFrame) machine.ChangeState(machine.Current == steady ? blink : steady);
        machine.Tick();
    }
}

The first ChangeState has no state to leave: Current is null, and ?. skips the call to Exit. Section 1 warned that ?. misses Unity's fake null; that is about destroyed Unity Objects, and the states are plain C# objects, so ?. is safe here. Current has a private set, so no script can swap the state without going through ChangeState and its Exit and Enter.

The order inside ChangeState matters whenever two states touch the same thing. Exit undoes what the old state changed, then Enter sets up the new one, so the new state has the last word. If a DarkState's Enter switched the lamp off and ran before BlinkState's Exit, that Exit would switch the lamp back on in the dark state. The StateMachine is a plain class too: the beacon, a turret and an enemy each make their own with new and call its Tick from their Update.

challenge icon

Challenge

Medium

Hold Space to sneak. WalkState and SneakState are ready in PlayerStates.cs: their Enter and Exit log what happens (Walk: enter, Sneak: exit...), and their Tick calls the player's Move(). Write the machine that runs them.

  • In StateMachine.cs, write a plain class StateMachine with a public Current property that only the machine can set, a ChangeState(IState next) method that runs the old state's Exit, then the new state's Enter, and a Tick() method that runs the current state's Tick.
  • The player asks for its state every frame, so ChangeState with the state that is already current does nothing: no Exit and no Enter.
  • In Player.cs, add a StateMachine field named machine. In Start, make the machine and both states (each takes the player) and start walking. In Update, change to sneaking while Space is held and to walking otherwise, then tick the machine.

Press Play, walk, hold Space and walk on, then Check.

Try it yourself

// StateMachine: Current, ChangeState and Tick
quiz iconTest yourself

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

All lessons in Game Architecture in Unity