Finite State Machines: Giving Characters a Mind of Simple Parts
A character that seems to think is often a handful of named states and the rules for moving between them; the finite state machine stays useful exactly as long as those rules stay few enough to hold in one's head.

Watch a guard in an old stealth game for long enough and a curious thing happens: the illusion of a mind begins to fray, and through the gaps one can see the gears. The guard walks a route, pauses, turns, walks back. A sound makes him stop and look. If he sees you, he shouts and gives chase; if he loses you, he searches for a while, mutters, and returns to his route. The behaviour feels alert and almost human, yet it is built from a short list of named conditions and a small set of rules for passing between them.
That structure is a finite state machine, one of the oldest ideas in computing and one of the most useful in game development. It says that an object is always in exactly one of a limited number of states, that each state determines how the object behaves, and that certain events or conditions move it from one state to another. The guard is patrolling, or investigating, or chasing, or searching, never two at once, and the moment he hears a noise is the moment the machine takes one step along a defined path.
This essay looks at the parts of such a machine, the two most common ways of writing one in C#, the hierarchical form that keeps larger machines manageable, the Unity Animator, which is itself a state machine wearing the costume of an animation tool, and finally the slow failure that overtakes every state machine allowed to grow without discipline, when the arrows between the states multiply until no one can follow them.
States, transitions and events
A state is a named mode of behaviour together with whatever the object does while it remains in that mode. In the patrolling state, the guard walks between waypoints and scans ahead; in the chasing state, he runs toward the last place he saw the player. States frequently carry three kinds of logic: something done once on entering, such as playing a shout or picking a new destination, something done every frame while inside, and something done once on leaving, such as stopping a looping sound. Keeping these three moments distinct removes a surprising number of bugs.
A transition is a rule for leaving one state and entering another. It names a source state, a destination state, and the trigger that causes the move. The trigger may be an event, a discrete thing that happened, such as the player being spotted or a timer expiring; or it may be a condition checked continually, such as health falling below a quarter. The difference matters in practice, because events fire once and are easy to reason about, while conditions must be polled and can flicker back and forth across a threshold.
The finite in the name is a real constraint and a real virtue. Because the set of states is known in advance, one can draw the whole machine on a single sheet of paper as circles joined by labelled arrows, and that drawing is a complete specification of the behaviour. A designer can point at it and ask why there is no arrow from searching back to chasing; a programmer can look at a bug report and say which arrow must have fired. Few other structures in game code are so easily shared between people who think in pictures and people who think in code.
Above all, the state machine answers the question that sprawling behaviour code always fails to answer: what is this object doing right now? Without states, a character's script tends to accumulate boolean flags such as isAttacking, isStunned and isClimbing, each checked in different places, until some combination arises that nobody intended, a character both stunned and attacking at once. A single current state variable makes those contradictions impossible by construction, since the object can only ever be in one place on the diagram.
The enum and the switch
The simplest implementation in Unity is a C# enum listing the states, a field holding the current one, and a switch statement inside Update that runs different code for each case. An enum named GuardState with values Patrol, Investigate, Chase and Search, and a field of that type, is enough to begin. Each case does its per-frame work and, when a condition is met, assigns a new value to the field. It fits on one screen, it is easy for a newcomer to read, and for a small machine it is often the correct choice.
Its weaknesses appear as the machine grows. Enter and exit logic has no natural home, so it ends up scattered through the cases or handled by a separate method that must be remembered every time the state changes. Data used only by one state, such as the timer for how long to search, lives as fields on the whole component and clutters it. As cases lengthen, the switch becomes a long column of unrelated behaviours sharing a single scope, and changing one state risks breaking another through a variable they both happened to touch.
A modest improvement keeps the enum but routes every change through a single method, often called ChangeState, which runs the old state's exit code, sets the field, and runs the new state's entry code. This one discipline repairs most of the damage, because there is now exactly one place where transitions happen, one place to log them, and one place to put a breakpoint when a character mysteriously stops chasing. Many shipped games use nothing more elaborate than this for their simpler creatures.
The State pattern
When states grow rich enough to deserve their own code, the classic answer is the State pattern described in the Gang of Four's Design Patterns. Each state becomes its own class implementing a shared interface, with methods such as Enter, Tick and Exit. The character holds a reference to its current state object and simply forwards each frame's call to it. Changing state means calling Exit on the old object, swapping the reference, and calling Enter on the new one. The switch statement disappears entirely, replaced by ordinary method dispatch.
The gains are organisational. A ChaseState class contains everything about chasing and nothing else: its own fields, its own helpers, its own decision about when to give up. It can be read, tested and modified in isolation. New states can be added without touching existing ones, which suits a team where several people work on behaviour at once. States can even be reused between characters, a generic FleeState shared by deer and frightened peasants alike, each passing in its own speed and safe distance.
The pattern has costs that are worth stating plainly. There are more files and more indirection, and a reader must open several classes to understand a behaviour that once fit in a single switch. States need some way to reach the character they belong to, usually a reference passed to their constructor or to Enter, and some way to request a transition, which tempts states into knowing about one another. Where each state constructs the next directly, the coupling the pattern was meant to remove quietly returns through the side door.
Machines within machines
Flat state machines repeat themselves. Suppose a guard can be killed at any moment, whatever he is doing. In a flat machine, every state needs its own arrow to the dead state, and every new state added later must remember to include it. The same is true for being stunned, for hearing an alarm, for any interruption that applies across the board. These duplicated arrows are tedious to write and easy to forget, and a forgotten one produces a guard who keeps patrolling after his health has fallen to zero.
A hierarchical state machine solves this by letting states contain other states. The guard's top level might have only two states, Alive and Dead, with a single transition from one to the other when health reaches zero. Inside Alive sits a sub-machine containing Patrol, Investigate, Chase and Search. When an event arrives, the innermost active state gets the first chance to handle it; anything it ignores passes up to its parent. The arrow to Dead is written once, on Alive, and applies to every state nested within it.
This idea was formalized by David Harel in his statecharts, which also introduced concurrent regions, where an object occupies a state in two independent sub-machines at once, a character's legs walking or running while its upper body aims or reloads. Games use the same trick constantly, whether or not they use the name, because it is the natural answer when two aspects of behaviour are genuinely independent. Combining them in a single flat machine would require a state for every pairing, which multiplies quickly into absurdity.
The Animator as a state machine
Unity developers meet a state machine long before they write one, because the Animator Controller is exactly that. Its boxes are states, each usually playing an animation clip or blend tree; its arrows are transitions; and its conditions are evaluated against parameters of type Float, Int, Bool or Trigger, set from scripts through SetFloat, SetBool and SetTrigger. The Any State node is a source from which a transition can fire regardless of the current state, Unity's flat answer to the interruption problem, and sub-state machines provide a form of nesting.
The Animator also has its own peculiarities that a general state machine does not. Transitions take time, cross-fading from one clip to the next over a set duration, so for a moment the character is visually in two states at once. The Has Exit Time option lets a transition wait until a clip reaches a given point, which suits an attack that should finish its swing. A Trigger parameter resets itself once consumed, behaving like an event, whereas a Bool persists like a condition, and confusing the two is a classic source of stuck animations.
It is tempting to put all of a character's logic into the Animator, and Unity even allows it through StateMachineBehaviour scripts, which receive callbacks such as OnStateEnter, OnStateUpdate and OnStateExit when a state is active. For small things this is convenient. For gameplay, many teams prefer to keep the authoritative state machine in code and treat the Animator as a display that follows it, because animation timing, blending and layering make the Animator's notion of the current state slightly fuzzy, and gameplay decisions should not depend on how far a cross-fade has progressed.
When the arrows multiply
The decline of a state machine follows a predictable course. It begins with four states and five transitions, a clear drawing everyone understands. Then a designer asks for a crouch, a dodge, a ledge grab, a stagger, and each new state needs arrows to and from most of the others. In a fully connected machine of n states there are n times n minus one possible transitions: twelve for four states, thirty for six, ninety for ten. Long before the full count is reached, the diagram has become a nest of crossing lines that nobody can audit.
This transition explosion is less a flaw of state machines than a signal that one has been asked to do too much. The first remedy is hierarchy, gathering states that share exits into a parent so their common arrows collapse into one. The second is separation, splitting independent concerns into parallel machines, so that locomotion and combat no longer multiply each other. The third is honesty about the tool: when behaviour depends on weighing many competing goals, behaviour trees or utility systems may express it better than any arrangement of arrows.
Even so, the finite state machine remains the first tool most game programmers reach for, and for good reason. A villager in a game like Crown & Ashes, where a settlement builds by day and must survive the Hunger by night, could be described in a handful of states that a designer can read at a glance. That legibility is the real gift. A machine one can draw is a machine one can reason about, and a character one can reason about is a character whose strange behaviour, when it comes, has an explanation sitting on the diagram.


