If you’ve ever been spotted by a guard who shouted, chased you, then gave up and wandered back to their post, you’ve watched a finite state machine (FSM) at work. FSMs are the oldest and still one of the most widely used tools for game AI, because they map almost perfectly onto how we describe enemy behavior in plain English: “the enemy is patrolling, until it sees the player, then it chases.”

What an FSM actually is

A finite state machine is made of three things:

  • States — the discrete “modes” an agent can be in (Patrol, Chase, Attack, Flee). The agent is in exactly one state at a time.
  • Transitions — the rules for moving between states.
  • Conditions / events — what triggers a transition (sees player, health < 20%, lost sight for 5s).

That’s the whole idea: at any moment the agent sits in one state doing that state’s behavior, and each tick it checks whether any transition’s condition is met. If so, it switches.

The canonical example

A classic melee enemy:

        sees player            in range
Patrol ───────────────▶ Chase ───────────▶ Attack
   ▲                      │                   │
   │  lost player (5s)    │  health < 20%     │ health < 20%
   └──────────────────────┴───────────┬───────┘
                                       ▼
                                     Flee
  • Patrol: walk a waypoint loop. Transition to Chase when the player enters the vision cone.
  • Chase: path toward the player’s last known position. Transition to Attack when in melee range, or back to Patrol if the player is lost for 5 seconds.
  • Attack: swing. Transition to Flee if health drops below 20%.
  • Flee: run to cover.

What it looks like in code

The simplest useful implementation is an enum plus a switch:

enum State { Patrol, Chase, Attack, Flee }
State current = State.Patrol;

void Update() {
    switch (current) {
        case State.Patrol:
            DoPatrol();
            if (CanSeePlayer()) current = State.Chase;
            break;
        case State.Chase:
            MoveTowardPlayer();
            if (InAttackRange())      current = State.Attack;
            else if (LostPlayer(5f))  current = State.Patrol;
            break;
        case State.Attack:
            SwingWeapon();
            if (Health < 0.2f) current = State.Flee;
            break;
        case State.Flee:
            RunToCover();
            break;
    }
}

For anything bigger, teams usually promote each state to its own object with Enter(), Update(), and Exit() methods — that Enter/Exit pair is where you start/stop animations, play a bark (“Over here!”), or reset a timer.

Why FSMs endured

  • Legible. A designer can read the state diagram and know exactly what the AI will do. There are no surprises.
  • Debuggable. When something looks wrong, you print the current state. The bug is almost always a missing or mis-ordered transition.
  • Cheap. A switch costs nothing. You can run thousands of them per frame.
  • Deterministic. Great for behavior you want to feel readable to the player — the “tells” that let players learn and counter enemies.

Pac-Man’s ghosts are the textbook case: each ghost is essentially a tiny FSM flipping between Chase, Scatter, and Frightened, and the whole game’s tension comes from reading those states.

Where FSMs break down

The Achilles’ heel is state explosion. Every new capability tends to multiply transitions. Add “reload” and “take cover” to a shooter enemy and you suddenly need transitions from every combat state into and out of them. The diagram turns into spaghetti, and adding one feature risks breaking three others.

Two common answers:

  • Hierarchical FSMs (HFSMs). Group related states under a super-state. A Combat super-state contains Attack, Reload, and TakeCover; a single “player fled” transition on Combat handles the exit for all of them, instead of one per child. This collapses a lot of duplicate edges.
  • Behavior Trees. When logic gets deeply conditional, many studios move to behavior trees, which express priorities and fallbacks as a tree of tasks rather than a web of transitions. BTs largely supplanted flat FSMs for complex AAA enemies in the 2000s — but they’re often described as “FSMs that scale,” and plenty of BT leaf nodes are themselves tiny FSMs.

The takeaway

FSMs are not a legacy curiosity — they’re the right tool whenever behavior is modal and readable: a handful of clear states, obvious transitions, and a designer who needs to reason about it at a glance. Reach for an HFSM when the transitions start duplicating, and a behavior tree when priority and fallback logic dominates. But the mental model you build with a simple Patrol → Chase → Attack machine is the foundation everything else is built on.

Next in this series: Behavior Trees, and why “selectors” and “sequences” are all you really need to understand them.