using XFG.AI.FSM.HFSM;The HierarchicalStateMachine module extends IStateMachine with support for parent/child state trees, enabling complex behavior modeling while keeping logic modular and maintainable.
This document describes the architecture, design goals, and usage patterns for the hierarchical FSM layer.
For the base FSM, see:
StateMachine ReadMe
For Serializable FSM support, see:
Serializable State Machine - ReadMe
For async support, see:
Async StateMachine - ReadMe
For Pushdown FSM support, see:
Pushdown State Machine - ReadMe
A Hierarchical Finite State Machine (HFSM) is an extension of a traditional FSM that organizes states into a parent/child hierarchy, allowing complex behaviors to be modeled in a clean, modular, and scalable way.
Instead of every state existing at the same level, an HFSM introduces layers of abstraction:
- Parent states define shared behavior, rules, and transitions.
- Child states inherit that behavior and add their own specialized logic.
- Transitions can occur at any level of the hierarchy.
- Enter/Exit events propagate through the hierarchy in a predictable order.
This structure mirrors how real gameplay logic is often organized:
- Movement → Grounded → Running
- Combat → Melee → Combo
- AI → Alert → Chase → Attack
HFSMs reduce duplication, improve clarity, and scale cleanly as complexity grows.
HFSM allows states to be organized into parent/child relationships:
- Parent states contain shared logic
- Child states override or extend behavior
- Transitions may occur at any level
- Enter/Exit events propagate through the hierarchy
Parent states can define:
- Shared movement logic
- Shared animation layers
- Shared message handling
- Shared transitions
Child states inherit this behavior automatically.
When transitioning between hierarchical states, the machine guarantees:
- Exit from deepest child → up to common ancestor
- Enter from common ancestor → down to new child
This ensures predictable and engine‑grade behavior.
HFSM is implemented as an extension layer:
- No changes to the base
IStateMachine - Synchronous and async states both supported
- Works seamlessly with message routing
- Works with any state ID enum
Where:
Groundedis the parent of bothIdleandRun
State Tree: Grounded ├── Idle └── Run
Transition: Idle → Run
Propagation Order:
Exit: Idle
(common ancestor = Grounded)
Enter: Run
Diagram:
[Grounded]
├── [Idle] -- EXIT
└── [Run] -- ENTER
Where:
Groundedis the parent ofRunAirborneis the parent ofJumpGroundedandAirborneshare no parent (siblings at root)
State Tree: Root ├── Grounded │ ├── Idle │ └── Run └── Airborne ├── Fall └── Jump
Transition: Run → Jump
Propagation Order:
Exit: Run
Exit: Grounded
(common ancestor = Root)
Enter: Airborne
Enter: Jump
Diagram:
[Root]
├── [Grounded]
│ └── [Run] -- EXIT
└── [Airborne]
└── [Jump] -- ENTER
Where:
Combatis the parent of bothAttackandCombo
State Tree: Combat ├── Attack └── Combo
Transition: Attack → Combo
Propagation Order:
Exit: Attack
(common ancestor = Combat)
Enter: Combo
Diagram:
[Combat]
├── [Attack] -- EXIT
└── [Combo] -- ENTER
State Tree: Root ├── Movement │ ├── Idle │ └── Run └── Combat ├── Attack └── Recover
Transition: Idle → Attack
Propagation Order:
Exit: Idle
Exit: Movement
(common ancestor = Root)
Enter: Combat
Enter: Attack
Diagram:
[Root]
├── [Movement]
│ └── [Idle] -- EXIT
└── [Combat]
└── [Attack] -- ENTER
HierarchicalStateMachineExtensions
RegisterChildStateRegisterParentStateChangeStateHierarchicalGetParentGetChildren
IHierarchicalState (optional)
ParentIDChildrenIDs
Hierarchy is defined explicitly through registration.
// -------------------------------
// Example Parent State
// -------------------------------
public class GroundedState :
IStateMachine<PlayerMachine, PlayerStateID, PlayerMessage>.IState
{
public PlayerMachine Machine { get; set; }
public PlayerStateID ID => PlayerStateID.Grounded;
public void OnStateEnter(PlayerStateID prev, object[] args)
{
Machine.EnableGravity(true);
}
}
// -------------------------------
// Example Child State
// -------------------------------
public class RunState :
IStateMachine<PlayerMachine, PlayerStateID, PlayerMessage>.IState,
IHierarchicalState<PlayerStateID>
{
public PlayerMachine Machine { get; set; }
public PlayerStateID ID => PlayerStateID.Run;
public PlayerStateID ParentID => PlayerStateID.Grounded;
public void OnStateUpdate()
{
Machine.Move(Machine.Input.MoveVector);
}
}RegisterState(new GroundedState());
RegisterState(new RunState());
RegisterChildState(PlayerStateID.Grounded, PlayerStateID.Run);ChangeStateHierarchical(PlayerStateID.Run);This will:
- Enter Grounded (if not already active)
- Enter Run
Use this module when your gameplay requires:
- Shared logic across multiple states
- Clean separation of parent vs. child behavior
- Complex AI or animation state trees
- Modular and scalable state organization
HFSM keeps your logic clean, predictable, and easy to extend.
Hierarchy should simplify logic, not complicate it.
HFSM is optional and layered on top of the base FSM.
Parent/child relationships are explicit and easy to reason about.
Enter/Exit propagation is deterministic and ordered.
