A visual editor for building Finite State Machines (FSM) and Hierarchical FSMs (HFSM) inside Unity. Design your agent behaviors as node graphs, save them as assets, and run them at runtime without writing glue code for every state.
Built with Unity's GraphView on top of a runtime layer that uses Dynamic Expresso to evaluate transition conditions written as plain C# expressions.
Example video: https://youtu.be/0gz49TAXLa8
- Visual FSM editor with drag-and-drop nodes and connections
- Support for hierarchical FSMs: any FSM asset can be used as a state inside another FSM
- Transition conditions written as C# expressions, evaluated at runtime (no recompiling)
- Assignments on transitions to prepare the blackboard for the next state
- Auto-detection of state scripts using reflection. Add a new
Stateclass and it shows up in the editor - Public fields on states are exposed in the node for per-instance configuration
- Shared blackboard per FSM instance with support for binding scene objects
- Save/load graphs as ScriptableObject assets
- Editor state is preserved across script recompilations
- Unity 2022.3 LTS or newer (developed and tested on Unity 6)
- Dynamic Expresso (included via NuGet or as a DLL in the project)
Window > FSM Graph Tool opens the editor window. From there you can create a new graph, save it, or load an existing one.
Right-click on the graph to open the search window. You can add:
- State nodes: any class inheriting from
Statein your project shows up here automatically - FSM nodes: any existing FSM graph asset can be dropped in as a sub-FSM (this is how you build HFSMs)
Draw a connection from the output of a state to the input of another. Then add a transition and write the condition as a C# expression, for example:
WormDetector.DetectedObject != null
You can also assign values to the blackboard when the transition fires:
Target = WormDetector.DetectedObject
Add an FSMAgent component to a GameObject and assign your graph asset. Optionally add a BlackboardObjectBinder to expose scene objects (detectors, controllers, etc.) to the blackboard so your expressions can reference them.
Hit Play. The agent will build the FSM from the graph, initialize the blackboard, and start ticking.
States are plain C# classes that inherit from State. Public fields of type string, int, float or bool are exposed automatically in the editor.
public class WanderState : State
{
public string WanderPointsParentName;
public float WanderSpeed = 5f;
public float WaitTimeBetweenPoints = 0f;
public float ReachPointRadius = 0.2f;
public override void OnEnterState() { /* ... */ }
public override void OnTick() { /* ... */ }
public override void OnExitState() { /* ... */ }
}That's it. The state is picked up by the editor and can be added to any graph.
The tool is split in two layers:
Editor layer builds the graph using GraphView. Nodes and connections are serialized into an FSMGraphSaveDataSO (a ScriptableObject) that holds state IDs, positions, transitions, condition expressions and any per-node field overrides.
Runtime layer reads that ScriptableObject and builds a FiniteStateMachine at runtime. States are instantiated via reflection using the type name stored on each node. Transitions are wrapped in a Transition object holding a Condition that gets compiled by Dynamic Expresso the first time it runs, using the blackboard as its variable context.
Because FiniteStateMachine itself implements the same IState interface as regular states, an FSM can act as a state inside another FSM. That's what makes HFSMs work.
The repo includes a demo scene with two agents:
- Chicken: uses an HFSM. Top level handles "eat routine vs flee from wolf". The eat routine is itself an FSM (
EatFSM) with wander, reach worm and eat worm states - Wolf: a simple FSM that wanders and chases nearby chickens
Both agents reuse the same four states (Wander, ReachTarget, EatTarget, FleeFromTarget) with different blackboard bindings, showing how modular states can be shared across different behaviors.
- Conditions and assignments are written as strings, so typos aren't caught until runtime. Autocomplete for blackboard keys is on the wishlist
- You need to know the properties of objects bound through
BlackboardObjectBinderto write expressions against them - GraphView is not the most documented Unity API, so extending some parts of the editor takes some digging
- Dynamic Expresso for the runtime expression evaluation
- Indie Wafflus node-based dialogue system tutorial series, which was a big help for getting up to speed with GraphView
MIT. See LICENSE for details.
Marc Sans Cormenzana · LinkedIn · marcsans1212@gmail.com