Enemy State Machines
Every enemy you build this year — the patrolling guard, the turret that shoots, the boss with three phases — is the same idea: a thing with a small set of behaviors, one of which is active, and the conditions that trade between them. This is the pattern reference, from the guard in Unit 4 to the boss in Unit 8.
What a state machine IS (in AP words)
A state machine is state stored in fields (1.3), selection choosing between behaviors (AAP-3), and Update providing the iteration that asks the conditions over and over. The exam's definition of an algorithm — sequencing, selection, iteration — is the whole shape of an enemy controller:
private void Update() // ITERATION - runs ~60 times a second
{
// SELECTION - which behaviour is active right now?
// SEQUENCING - run exactly one of them
}
The guard's machine (Unit 4)
The enemy controller you build in Unit 4 is a machine whose states are mostly implicit — they exist as conditions, not as a named enum. That is a legitimate design, and worth understanding before you decide whether to upgrade it:
| State | What makes it active | Transition out |
|---|---|---|
| PATROL | nothing else is true — it is the default behaviour | → CHASE once the player is inside the aggro radius |
| CHASE | the player is within range, so the chase condition matches | → PATROL when the player leaves that radius |
| ATTACK | a contact event, not a move state — it fires during patrol or chase | → back to whatever movement state is still true, after a cooldown |
The elegant part: there is no "return to patrol" line anywhere. The chase sits inside an if; when the if stops matching, the enemy simply falls back to its default behavior. The patrol was never switched OFF — it was outvoted. Drawn on paper (4.5), the machine is four boxes and three arrows; coded, it is three ifs and a cooldown.
Notice something important about ATTACK: it is not a movement state at all. It is triggered by physics, so it can happen while the enemy is patrolling or chasing. That is the single most common design mistake in a first state machine — assuming every state must be mutually exclusive with every other.
The turret, minimized
Even the turret is a two-state machine: SHOOTING (in range AND off cooldown) and WAITING — and the cooldown pattern (3.3) is what turns "in range" into a rhythm. A timer plus a comparison IS a state machine with a clock for a brain. This is why the cooldown pattern reappears everywhere: attack rates, contact damage, jump mercies (6.3), turn gates (10.2d).
Making states explicit (the enum upgrade)
When a machine grows past "a couple of ifs," named states earn their ceremony. The upgrade has four parts, and you can write them yourself from the descriptions alone:
- An enum declaring the states as named values, so the compiler can catch a typo that a string could not
- One field holding the currently active state
- A switch on that field inside the update loop, with one case per state
- Each case assigning the next state when its condition is met — that assignment is the transition
Two rules make explicit machines trustworthy: one state active at a time (if two can be active, you did not need a state machine), and every transition has a condition you can read aloud ("recovering ends when the interval has elapsed"). A machine whose transitions you cannot narrate is a pile of ifs wearing a costume.
Do not assume the animator agrees with you
A state machine in code and a state machine in the Animator are two different machines that happen to share a vocabulary, and they do not have to use the same conventions. This project proves it. The Player's controller and the enemy's controller were built by different hands and they disagree on almost everything:
| Player | Enemy | |
|---|---|---|
| Direction parameter | WalkDir: 0 = up, 1 = sideways, 2 = down | Direction: 0 = right, 1 = up, 2 = left, 3 = down |
| Idle states? | Yes — idle and walk states | No — walk states only |
| Left and right | One sideways clip, mirrored with flipX | Separate left and right clips, no flipX at all |
The lesson: read a state machine before you drive it. Two controllers that
both have a direction parameter can still mean completely different
things by 0. When you drive someone else's machine — including
one you wrote last month — open the Animator window and check its
parameters rather than assuming they match the last one you met.
The boss's phase layer (Unit 8)
The boss stacks a second machine ON TOP of the behavior one: phases — a one-way ladder driven by health thresholds (8.2). Two design facts make phases work:
- Phase changes fire DOWNWARD ONLY (currentPhase guards in the threshold check), so a phase entrance never re-runs
- Phase changes swap NUMBERS via a phase table (8.4) — cooldowns, speeds, attack sets — so the player SEES difficulty change without a single new mechanic being taught
A phase is "the same machine with different constants" — which is also the exam's cleanest example of managing complexity: one table, one switch statement, six difficulty knobs.
Debugging a state machine
- Instrument the trade: Debug.Log the state name on every transition, watch the console flicker at boundaries — a machine that flickers CHASE/PATROL at the range edge is telling you the condition has no hysteresis (a bigger chase-in radius than chase-out radius fixes it; that gap is what 6.3 calls mercy, pointed at AI instead of the player)
- Reproduce before you theorize: stand where the tester stood, in the state they were in. Most "AI bugs" are boundary bugs at the transition line.
- Check the guards: a transition that fires every frame is an unguarded if; a transition that never fires is a wrong comparison or a wrong tag. Both are one Debug.Log away.