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
EasyA 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
tapsand shows it intapsText, asTaps: 3. AfterroundTimeseconds (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
}
}
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