Unit Action Graph

Hierarchical finite state machine editor for authoring character behavior with parallel layers, transitions, and conditions.

The Unit Action Graph is a Hierarchical Finite State Machine (HFSM) editor for authoring character behavior. It uses the gs_graphcanvas framework with a StateMachineGraph topology — multidirectional perimeter connections, tick-based state evaluation, and polymorphic transition conditions.

 

Contents


Opening the Editor

Open the Unit Action Graph editor from the O3DE Editor menu: GS Tools > Unit Action Graph Editor.

The editor manages a single .unitaction file containing all layers. Use File > New to create one, or File > Open to load an existing graph.


Multi-Layer Model

A .unitaction file is a container holding multiple layers, each an independent state machine graph. Layers are managed through the Layer Sidebar dock:

  • Add — Create a new layer with an Entry node
  • Remove — Delete a layer
  • Rename — Double-click to rename
  • Duplicate — Copy an existing layer
  • Priority — Set in the Layer Details panel (higher priority overrides lower)

Click a layer name to open it as a graph tab. All layers save together as one file.


Perimeter Connections

Unlike flow and data-flow graphs that use slot-based bezier curves, state machine graphs use perimeter connections — straight arrows drawn from the edge of one state node to the edge of another. This gives the graph a traditional state machine diagram appearance.

When multiple connections exist between the same pair of nodes, they are offset for readability. Arrows include arrowheads at the target node.


Nodes

NodePurposeTransitions InTransitions Out
EntryMarks the initial stateNoYes (one connection to the starting state)
StateA behavior state with OnEnter/OnTick/OnExit lifecycleYesYes
Compound StateA state containing a nested sub-state-machineYesYes

Entry Node

Auto-spawned in every new graph. Cannot be deleted or duplicated. Has a single outgoing connection to the initial state. Cannot be transitioned into.

State Node

The standard state. Represents a character behavior (Idle, Walk, Run, Attack). Each state carries its own list of outgoing TransitionDescriptor entries — one per outgoing connection.

Compound State Node

A state that contains an entire nested state machine. When entered, the compound state initializes and runs its sub-graph. When exited, the sub-graph stops. Used for complex behaviors with internal sub-states (e.g., a Jump state with Rising/Apex/Falling sub-states).


Transitions

Transitions are the connections between states. Each transition has:

  • Priority — Integer value. When multiple transitions are valid on the same tick, the highest priority fires.
  • Conditions — A polymorphic list of TransitionCondition objects. All conditions must be satisfied for the transition to fire.

Inspecting Transitions

Click a transition arrow in the graph to select it. The Inspector Panel shows:

  • “Transition: Source -> Destination” header
  • Priority field
  • Conditions list with a type picker to add new conditions

Transition Summary on Nodes

When a state node is selected, the inspector shows a summary of all outgoing transitions below the node’s properties. Each entry shows "P{priority}: -> {destination} [{N} conditions]" with a “Select” button to jump to that connection’s inspector.

Auto-Management

Transition descriptors are created and removed automatically when connections are added or removed in the graph. No manual descriptor management is needed.


Built-in Conditions

ConditionDescription
VariableCompareConditionCompares a named variable to a value using a comparison operator (==, !=, <, >, <=, >=)
TimeElapsedConditionFires after a specified number of seconds in the current state. Reads the __stateTime auto-variable.
VariableTrueConditionFires when a named boolean variable is true

Parallel Layers

The defining feature of the Unit Action Graph. Multiple layers evaluate simultaneously, each running its own independent state machine. All layers share the same variable context, enabling cross-layer communication.

Example layout:

UnitActionGraph
├── Layer: Movement (priority 0)   — Idle, Walk, Run, Jump
├── Layer: Action (priority 1)     — None, Attack, Interact
└── Layer: Rotation (priority 2)   — FreeRotation, Locked, Modulated

Higher-priority layers can restrict or override lower-priority outputs. Each layer produces a state output that feeds into the character control system.

This solves the classic “jump while moving” problem — the Movement layer handles lateral motion while the Action layer handles the jump impulse, both evaluating simultaneously without conflicting.


Extending

Custom States

Subclass BaseNode and implement IStateMachineNode:

void OnEnter(GraphExecutionContext& context) override;
void OnTick(GraphExecutionContext& context, float deltaTime) override;
void OnExit(GraphExecutionContext& context) override;

Register with GS_AUTO_REGISTER_NODE_FOR(MyStateNode, "unitaction").

Custom Transition Conditions

Subclass TransitionCondition, add AZ_RTTI, and implement Reflect(). The inspector type picker auto-discovers new conditions via SerializeContext::EnumerateDerived().


Current Status

Implemented:

  • Perimeter connection rendering (engine-level)
  • Multi-layer container editor with sidebar
  • HFSM runtime architecture (StateMachineEvaluator, ParallelLayerEvaluator)
  • All node types (Entry, State, Compound State)
  • Transition inspector with connection selection
  • Built-in transition conditions

Not yet implemented:

  • GS_UnitContext integration (connecting evaluator to unit components and Movers)
  • Compound State sub-graph editing via double-click in the editor
  • Tag-based transition groups and free-entry states
  • GS_CharacterActionComponent bridge to MoverContextRequestBus

See Also