# Unreal Engine: State Machines

*2025-10-22*

> Notes taken from the seventeenth week of Game Programming Foundations


This week followed on from the [AI fundamentals]({{< relref "/posts/2025/unreal-engine-16-introduction-to-ai" >}}) and dove into [**state machines**](https://dev.epicgames.com/documentation/unreal-engine/state-machines-in-unreal-engine) – the design pattern that gives AI behaviour its structure .

For future reference, the example project for this week's content was committed and uploaded here:

[sawnoff-studios/state-machine-demo](https://github.com/sawnoff-studios/state-machine-demo)

---

## Introduction to State Machines

A state machine is a design pattern that allows an object to change behaviour based on its internal state: distinct behaviours (states) with explicit rules for switching between them.

**The classic analogy: traffic lights.**

- **Red state** – cars must stop
- **Yellow state** – cars should prepare to stop
- **Green state** – cars can proceed
- **Transitions:** Red → Green → Yellow → Red

### Why use state machines?

- **Clarity and organisation** - behaviour lives in discrete state classes rather than one massive script
- **Maintainability** – adding or modifying behaviours becomes easier
- **Debugging** - easily see the AI's state and track transitions to identify issues
- **Reusability** - states can be shared between AI characters

### Common AI state flows

- **Guard AI:** Patrol → Investigate → Chase → Search → Return to Patrol
- **Companion AI:** Follow → Wait → Assist → Idle
- **Enemy AI:** Idle → Alert → Attack → Retreat → Dead
- **NPC AI:** Work → Eat → Sleep → Socialise

## Implementing the State Machine System

The core structure is two classes:

**`UStateMachine`**
- Holds the current and previous states
- Manages state transitions
- Updates the current state each frame
- Tracks its owner (the AI character using it)

**`UState`** - the base class each state inherits from, implementing three lifecycle functions:

```cpp
// Initialise state-specific variables, set up required
// components or systems, log state entry for debugging
EnterState();

// Execute main behaviour logic, check for transition
// conditions, update movement/animations
UpdateState();

// Clean up state-specific data, stop movements or
// actions, log state exit for debugging
ExitState();
```

Notice the lifecycle: enter, run, leave – the same shape as the ability lifecycle from the [GAS week]({{< relref "/posts/2025/unreal-engine-14-gameplay-ability-system" >}}), with `EndAbility` playing `ExitState`.

## Best Practices

- **Keep states simple** – each state has a single responsibility
- **Use logging for debugging:**

```cpp
UE_LOG(LogTemp, Warning, TEXT("AI entering Alert State"));
```

- **Visual debug information** - on-screen debug rendering showing the current state, so you can literally watch what the AI is thinking
- **Plan state transitions** - draw out states and their conditions before implementing; it exposes impossible situations and missing edge cases on paper rather than at runtime
- **Handle edge cases** – check for null pointers and invalid states; AI systems need to be robust
- **Consider state history** – the state machine tracking its previous state is useful for returning to prior behaviour (e.g. investigating, then resuming patrol)

## Key Takeaways

- **Separation of concerns** – each state owns one specific behaviour
- **Clear transitions** - well-defined rules for when states change
- **Easy debugging** – visual and logged feedback into what the AI is doing
- **Scalable design** – new states and behaviours slot in without touching the rest

---

## Notes on things that stood out

The pleasing thing about this week was how much of it was déjà vu – in a good way. The state machine is really the third appearance of the same architectural idea: discrete, self-contained behaviours with a lifecycle, whether that's animation states in the animation graph, gameplay abilities in GAS, or AI states here. Once you've internalised "enter, update, exit, and rules about switching," you keep meeting old friends.

The practical habit I'm taking forward: *draw the state diagram first.* The course's advice to plan transitions on paper sounds obvious. However, the guard flow (Patrol → Investigate → Chase → **Search** → Return to Patrol) has a subtle elegance - Search exists precisely because "lost the player" isn't the same state as "patrolling," and that's the kind of distinction you miss when you code states one at a time.
