Tutorial: Building a State Machine¶
StateMachine lets you describe behaviour as a set of named states connected by condition-driven transitions. No Update polling, no manual state tracking — each state defines its own running process and the transitions out of it. Built on the same Key + Process primitives you already use elsewhere.
By the end of this tutorial you'll have a door that opens on player approach, stays open for two seconds after the player walks away, then closes.
Prerequisites: Basic familiarity with the Process system, Conditions, and Events.
Mental Model¶
A StateMachine owns a list of State Nodes. Each node is:
- A Key that identifies the state.
- A State Process that runs while the state is active.
- A list of Transitions that move the machine to another Key when their condition fires.
stateDiagram-v2
[*] --> Closed
Closed --> Opening : PlayerNear
Opening --> Open : All Processes Done
Open --> Closing : PlayerFar (after 2s)
Closing --> Closed : All Processes Done
Transitions are subscription-based: when a state is entered, its transition listeners are set up. When the state exits, they're torn down. No polling.
1. Create the Keys¶
Each state is identified by a Key (a ScriptableObject). Create:
- Create → Jungle → Data → Key named Closed.
- Repeat for Opening, Open, Closing.
Keys are refactor-safe — renaming the asset doesn't break references.
2. Add the StateMachine¶
On the Door GameObject add a StateMachine component.
Add Component → Jungle → Processes → State Machine
Configure:
- startingState — drag Closed Key in. (Falls back to the first state if left empty.)
- states — empty for now; we'll add four.
3. Define Each State¶
Click + on states four times. For each entry:
| Field | What it is |
|---|---|
| State Value | Pairs a Key with the State Process to run while the state is active. |
| Transitions | Each transition has a condition and a target Key. |
Closed¶
- Key: Closed
- State Process: leave empty or set to a NoOp — the door just sits. Optionally, an animation that locks the door in the closed pose.
- Transitions:
- On Condition —
ConditionAdapterwrapping a "Player Within Range" condition. Target Key: Opening.
Opening¶
- Key: Opening
- State Process: a
TransformCommandor AnimationCommand that opens the door (animates rotation / position / animator state). - Transitions:
- All Processes Done — fires when the state's process finishes naturally. Target Key: Open.
Open¶
- Key: Open
- State Process: hold pose. Optionally a
WaitForDuration(2 seconds)chained with a check that the player has left. - Transitions:
- On Condition —
PlayerWithinRange == false. Target Key: Closing.
Closing¶
- Key: Closing
- State Process: animate door closing.
- Transitions:
- All Processes Done — Target Key: Closed.
Press Play. Walk near the door — it opens. Walk away — after the open animation finishes and the proximity condition flips, it closes.
4. Transition Condition Types¶
The picker on each transition's Condition field shows several built-ins:
| Condition | Fires When |
|---|---|
On Event (EventTransitionCondition) |
A configured IEvent raises. Subscribes on enter, unsubscribes on exit. Use for EventFromAsset, SignalEventFromHub, input events, anything. |
On Condition (ConditionAdapter) |
A regular Jungle Condition becomes valid. Polls each frame while the state is active. |
| All Processes Done | The state's State Process completed naturally. Subscribes to the state's completion event — no polling. |
| Wait One Frame | One frame after the state was entered. Useful for chaining states without sitting on an "empty" state. |
| Composite | Combines child conditions with All (every child must fire) or Any (first to fire wins). |
Mix freely on a single state — the first transition whose condition fires wins.
5. The Execution Frame¶
A StateMachine is a ControllableComponent. Its Begin/End is driven by an IExecutionFrame — by default the GameObject's enable cycle. On Begin the machine enters its startingState; on End it exits the current state.
Common alternative frames:
- Event Frame — begin on one
IEvent, end on another. Useful for "this state machine only runs during the boss fight". - Targeted Cycle Frame — bind to another component's cycle (an Attachable's
Attachedcycle, an Agent'sHoldingcycle). - Mono Lifecycle Frame — explicit
Start/OnEnable/ etc. choice.
6. Querying the Machine¶
From scripts or external Conditions:
| API | Returns |
|---|---|
CurrentState |
The currently running StateProcess. |
CurrentStateKey |
The Key of the current state. |
HasState(Key) |
Whether a node with the given Key exists. |
GetState(Key) |
The StateProcess for the given Key. |
TransitionTo(Key, callback) |
Force a transition to the given Key. Callback fires after the transition completes. |
The event OnStateChanged(Key previous, Key new) fires on every transition — wire it to UI, audio, debug.
7. Reactive Wiring on the Side¶
State Machines often pair with Reactors for per-state side effects without bloating the state nodes:
- A Reactor with an Event target on
OnStateChanged(via a small adapter) — runs different bodies depending on which state was entered. - A Reactor with a Signal target that fires
RaiseSignalOnOwnerTransmitter(SomeSignal)from inside a state's process — broadcasts that the state "did something" without coupling the state machine to the listener.
8. State Machine vs Reactor¶
Both run logic based on conditions. When to use which?
| Pick a... | When |
|---|---|
| StateMachine | Behaviour is naturally a mode/phase: only one running process at a time, transitions between modes are the central design. |
| Reactor | Multiple independent responses to triggers — they aren't mutually exclusive. |
A boss with three phases (idle → enraged → dying) is a StateMachine. A UI panel that animates two unrelated effects on different events is a Reactor.
You'll often want both — a StateMachine for the boss's phase, a Reactor on the same GameObject for the cross-cutting effects.
Next Steps¶
- Conditions overview — for the condition types you can plug into transitions.
- Reactor tutorial — typed reactive bodies that complement state machines.
- StateMachine reference — full API.
- Process system — the
StateProcessunderneath each node.