Menu
CoddyTech

Switching on the State

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

Each state of a game does different work every frame. A switch on the state field puts that work in one case per state, and each frame runs exactly one case. Changing state goes through one method, so the screen always matches the state. This boss fight has an intro, the fight and a victory screen:

public enum Phase { Intro, Fight, Won }

public class BossFight : MonoBehaviour
{
    public GameObject introPanel;
    public GameObject fightPanel;
    public GameObject winPanel;
    public int bossHp = 10;
    private Phase phase;
    private float timer = 3f;

    void Start()
    {
        Enter(Phase.Intro);
    }

    void Update()
    {
        switch (phase)
        {
            case Phase.Intro:
                timer -= Time.deltaTime;
                if (timer <= 0f) Enter(Phase.Fight);
                break;
            case Phase.Fight:
                if (bossHp <= 0) Enter(Phase.Won);
                break;
            case Phase.Won:
                break;
        }
    }

    void Enter(Phase next)
    {
        phase = next;
        introPanel.SetActive(next == Phase.Intro);
        fightPanel.SetActive(next == Phase.Fight);
        winPanel.SetActive(next == Phase.Won);
    }
}

Each case ends with break, because C# refuses to compile a case that runs on into the next one. When the intro's timer runs out, Enter(Phase.Fight) changes the phase, but the Fight case first runs on the next frame, because this frame has already picked its case. With separate if blocks one after another, a frame could start the fight and run fight code in the same frame.

Enter is the only place that changes phase. next == Phase.Fight is true for the fight panel only, so one call shows that panel and hides the other two. Work that belongs to entering a state, such as resetting a timer, goes in Enter too, and runs once instead of every frame.

challenge icon

Challenge

Easy

A tap race: how many times can you press Space in 5 seconds? The GameManager has the GameState enum (Ready, Playing, GameOver), a panel for each state, and Start calls SetState(GameState.Ready). Write Update and SetState.

In Update, switch on state:

  • Ready: Space starts a round. That press is not a tap.
  • Playing: each press of Space adds 1 to taps and shows it in tapsText, as Taps: 3. After roundTime seconds (5), the game is over.
  • GameOver: Space goes back to Ready.

SetState(GameState next) sets state and shows only the new state's panel. Entering Playing starts a round with 0 taps, Taps: 0 on the screen and roundTime seconds left; entering GameOver shows the result in resultText, as Taps: 3.

Press Play, race twice, then Check.

Try it yourself

using UnityEngine;
using TMPro;

public enum GameState { Ready, Playing, GameOver }

public class GameManager : MonoBehaviour
{
    public GameObject readyPanel;
    public GameObject playPanel;
    public GameObject gameOverPanel;
    public TMP_Text tapsText;
    public TMP_Text resultText;
    public float roundTime = 5f;
    public GameState state;
    private int taps;
    private float timeLeft;

    void Start()
    {
        SetState(GameState.Ready);
    }

    void Update()
    {
        // switch on state:
        // Ready: Space starts a round
        // Playing: Space counts a tap; when the time is up, the game is over
        // GameOver: Space goes back to Ready
    }

    void SetState(GameState next)
    {
        state = next;
        // show only the panel of the new state
        // a new round starts with 0 taps and roundTime seconds; at the end, resultText shows the taps
    }
}
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