Game State
Summary
Game state is the current mode or phase the game is in — main menu, playing, paused, game over — and the rules governing what's allowed to happen in each one. Explicitly tracking and checking game state is what stops the player from moving their character while the game is paused, or what makes the pause menu appear only when gameplay is actually running, rather than every system independently guessing whether it should be active right now.
Why This Matters
Without an explicit, shared understanding of "what mode is the game currently in," every system has to independently figure out whether it should be doing anything — should the player's movement script respond to input right now? Should enemies keep attacking? Should the timer keep counting down? Answering that question separately, and potentially inconsistently, in a dozen different scripts leads to bugs like a character still moving while a pause menu is open, or a death animation playing while the win screen is already showing. A single, explicit game state that every relevant system checks (or reacts to changes in) keeps the whole game's behavior consistent.
Mental Model
Game state is a stoplight everyone on the road obeys, not each driver guessing independently whether it's safe to go. A busy intersection without a shared signal would require every driver to negotiate individually with every other driver, every time — chaotic and unreliable. A stoplight gives everyone the same, unambiguous, shared answer to "should I be moving right now," and every driver's behavior is consistent because they're all reacting to the same signal. A game's state serves the exact same role for every system in the game.
Core Explanation
- Game state is usually represented as a small, closed set of named
modes. An
enum GameState { MainMenu, Playing, Paused, GameOver }captures the complete set of modes a game can be in — using anenumrather than loose booleans (isPaused,isGameOver) avoids contradictory combinations like both being true at once. - Systems check or react to the current state rather than deciding
independently. Player input handling checks "is the current state
Playing?" before responding to movement keys; it doesn't maintain its own separate notion of whether the game is active. - Transitions between states are usually the interesting, rule-governed
part. Moving from
PlayingtoPausedmight pause the game loop's simulation time, show a UI panel, and stop enemy AI — a state transition is often a specific, deliberate sequence of actions, not just flipping a label. - State changes are commonly broadcast as events, letting interested systems (UI, audio, AI) react without the state manager needing to know about every one of them directly — a direct application of [[CON-0024]].
Syntax / Theory
C# (Unity)
public enum GameState { MainMenu, Playing, Paused, GameOver }
public class GameStateManager : MonoBehaviour
{
public static GameState Current { get; private set; } = GameState.MainMenu;
public static event Action<GameState> OnStateChanged;
public static void SetState(GameState newState)
{
Current = newState;
OnStateChanged?.Invoke(newState);
}
}
public class PlayerMovement : MonoBehaviour
{
void Update()
{
if (GameStateManager.Current != GameState.Playing) return; // Guard on shared state.
HandleMovementInput();
}
}
C++ (Unreal — Game State / Game Mode)
UENUM()
enum class EGameState : uint8 { MainMenu, Playing, Paused, GameOver };
UCLASS()
class AMyGameMode : public AGameModeBase
{
public:
void SetGameState(EGameState NewState)
{
CurrentState = NewState;
OnGameStateChanged.Broadcast(NewState);
}
private:
EGameState CurrentState = EGameState::MainMenu;
};
Unreal has a built-in AGameStateBase/AGameMode framework specifically
for this responsibility — a purpose-built version of the same enum-plus-
broadcast pattern shown here, integrated with Unreal's networking and
level-transition systems.
Unreal Blueprint
A Blueprint-implemented Game Mode can expose a Current State variable
and a matching Event Dispatcher, letting other Blueprints branch on or
react to state changes the same way as the C++/C# examples.
Practical Example
A pause system uses game state both to stop gameplay and to control which UI is visible.
public class PauseController : MonoBehaviour
{
public void TogglePause()
{
if (GameStateManager.Current == GameState.Playing)
{
GameStateManager.SetState(GameState.Paused);
Time.timeScale = 0f;
}
else if (GameStateManager.Current == GameState.Paused)
{
GameStateManager.SetState(GameState.Playing);
Time.timeScale = 1f;
}
}
}
public class PauseMenuUI : MonoBehaviour
{
void OnEnable() => GameStateManager.OnStateChanged += HandleStateChanged;
void HandleStateChanged(GameState state) =>
panel.SetActive(state == GameState.Paused);
}
PlayerMovement, PauseMenuUI, and any future system all agree on
exactly one authoritative answer to "is the game currently paused" —
GameStateManager.Current — instead of each maintaining its own,
potentially inconsistent notion of it.
Common Mistakes
- Using scattered boolean flags instead of one explicit state.
isPaused,isGameOver,isInMenuas separate booleans allow impossible combinations (isPaused == trueandisGameOver == truesimultaneously) that anenum-based single state makes structurally impossible. - Letting individual systems decide independently whether they should be active, rather than checking or reacting to shared state — this is exactly the inconsistency (movement working during pause) game state exists to prevent.
- Forgetting to reset relevant systems on a state transition. Moving
from
GameOverback toPlaying(a restart) without resetting health, score, or enemy positions leaves stale state from the previous playthrough bleeding into the new one. - Overloading a single game state enum with unrelated concerns. Cramming both "what screen is showing" and "what difficulty is selected" into one state value conflates two independent axes that should be tracked separately.
Game Development Example
A multi-phase boss fight uses its own local state (distinct from the overall game state) to control which phase's behavior is currently active.
public enum BossPhase { Phase1, Phase2, Enraged, Defeated }
public class BossController : MonoBehaviour
{
private BossPhase phase = BossPhase.Phase1;
void Update()
{
switch (phase)
{
case BossPhase.Phase1: RunPhase1Behavior(); break;
case BossPhase.Phase2: RunPhase2Behavior(); break;
case BossPhase.Enraged: RunEnragedBehavior(); break;
case BossPhase.Defeated: break; // No behavior — fight is over.
}
}
}
This mirrors the overall game state pattern at a smaller scale — the boss fight has its own well-defined set of modes, and every piece of its behavior checks or reacts to the current phase rather than each attack pattern deciding independently whether it should run.
Best Practices
- Represent game state as a single, closed enum rather than several independent boolean flags.
- Route state changes through one authoritative place (a manager) rather than letting arbitrary systems mutate state directly.
- Broadcast state changes as events so interested systems can react without the state manager needing direct references to all of them.
- Explicitly reset relevant systems on transitions that require it (restarting a level, returning to a menu) rather than assuming a clean slate.
Exercises
- Implement a
GameStateenum withMainMenu,Playing, andPaused, and make aPlayerMovementscript only respond to input while the state isPlaying. - Take the
PauseControllerexample and add aGameOverstate that stops enemy AI and shows a game-over UI panel, reusing the existingOnStateChangedevent. - You're building a turn-based strategy game with states like
PlayerTurn,EnemyTurn,Animating, andVictory. Decide whether this should be one large state enum or several smaller, independent state machines (e.g. a separate "turn" state and "UI" state), and justify the trade-off. - Research the State design pattern (distinct from, but related to, this Concept's "game state") and explain how representing each state as its own class/object, rather than an enum checked everywhere, changes how transition logic is organized.
Related Concepts
- Scenes — game state and scene loading are often coordinated together
(loading a
GameOverscene, or toggling a state within a persistent gameplay scene), though they solve related but distinct problems. - Enums — the natural, structurally-safe way to represent a closed set of named states, preventing the impossible-combination bugs that scattered booleans allow.
- Events — state changes are commonly broadcast as events so interested systems can react without being directly wired to the state manager.
Further Reading
KNOWLEDGE_SCHEMA.md— GDKB's concept maturity ladder and cross-linking rules, which this document follows.- Unity documentation — Time.timeScale: https://docs.unity3d.com/ScriptReference/Time-timeScale.html
- Unreal Engine documentation — Game Mode and Game State: https://dev.epicgames.com/documentation/en-us/unreal-engine/game-mode-and-game-state-in-unreal-engine