Our platformer has one variable that decides what the entire game is doing. It holds one of eight words: booting, loading, the title screen, a level card, playing, the help screen, won, or game over.
Almost every question the code asks is downstream of that variable, and almost every category of bug it does not have is because that variable exists.
The problem with flags
The alternative, and the thing everyone writes first, is a set of separate true-or-false variables. Is the game started. Is it paused. Is the player dead. Is the level finished. Is the help screen open.
Five of those allow thirty-two combinations, and perhaps six of them mean anything. The rest are nonsense the code has to be defended against: paused and dead at once, help open while the level is finishing, started but also on the title screen.
The bugs this produces are the worst kind. They are rare, because they need a specific sequence of events. They are hard to reproduce, because that sequence is usually something like pressing pause while a level completes. And they present as something visually absurd, like two interfaces on screen simultaneously, which makes them look like a rendering problem rather than a logic one.
One variable holding one of eight words cannot enter an impossible combination. Not because it is checked, but because there is nowhere for the impossible combination to live.
Transitions are where things happen
The second half of the idea, and the more useful one, is that all the work goes into the moment of changing state rather than into the states themselves.
There is one function that changes it, and everything that must happen exactly once on entering a mode happens there. In our build: the interface is cleared on every transition, so no screen can leave a button behind. Touch controls are shown only when entering play. Entering the loading screen starts the tape screech. Entering a level card resets the level. Entering the win state fires the confetti, plays the birthday tune and records the score.
Because that is the only route in, none of those can happen twice and none can be forgotten. The confetti fires once because there is one line that fires it and it is on the edge into that state.
There is a concrete bug this fixed. The touch controls used to be visible for the whole session, which meant they sat on top of the title screen's own buttons and made them unpressable on a phone. The fix was one line in the transition: show them when entering play, hide them otherwise. If the visibility had been decided in five different places, it would have been five fixes and a sixth place somebody missed.

What each state changes
Once the variable exists, the rest of the game gets simpler rather than more complicated, because every part of it can ask one question.
The loop only advances the world while playing. On the title screen it still draws, which is why the title screen can animate. Paused draws but does not update, which is the entire implementation of pausing and it is one condition.
Input means different things. Space is jump while playing and start on the title screen. The same key, two behaviours, no ambiguity, because the state decides which.
Drawing is a straightforward branch on the state, and each branch knows exactly what belongs on screen because nothing else can be true at the same time.
The other kind of state machine
The same idea appears at a smaller scale inside a single character, and it is worth separating the two because they are often confused.
A character is idle, or walking, or in the air. Those are states too, with rules about which can follow which: you can go from walking to airborne, and from airborne to idle on landing. The drawing code picks a sprite from that state rather than working it out from velocities each frame.
Our chess build has a third example again: choosing a piece, choosing a destination, watching a capture play out, and waiting for the opponent to think. Clicks mean different things in each, and a click during a fight animation has to do nothing at all rather than start a second move.
Same structure, three different scales. It is one of the few patterns in game code that keeps being the right answer.
Where it stops being enough
To be fair about the limits, because "use a state machine" is not universal advice.
It handles things that are exclusive: you are either playing or paused, never both. It handles things that are simultaneous badly, and forcing them into it produces combinatorial names like playing-while-invulnerable-and-underwater, which is the flags problem wearing a disguise.
The rule of thumb we use is that the big mode of the game is a state, and the small independent facts about a character are separate values alongside it. Invulnerability after being hit is a countdown, not a state. Which way the character is facing is a number, not a state. Only the exclusive things get to be states.
What this means for a commission
It is invisible and it is why the interface behaves. Screens that clear properly, buttons that appear when they should, a pause that pauses.
It is also what makes a game testable. A test can put the game into a known state and assert what happens next, which is a large part of proving a game is actually finished.
And it is where the polish hangs. Level cards, confetti, a tune on winning: all of it lives on a transition, which is why adding a flourish to a well-structured game is an hour and adding it to a badly structured one is a fortnight.



