In this lesson, you will learn how to architect a robust, C++-based Finite State Machine (FSM) using a base class pattern to encapsulate state-specific logic and transitions.
Why Use a Base Class?
While Blueprint Behavior Trees are excellent for high-level decision making, sometimes you need a lightweight, high-performance FSM for specific actors like a turret or a door. By creating an UFSMState base class, you enforce a consistent structure where every state handles its own logic, entry, and exit.
The FSM Pattern
To implement this, you define a base class that holds pointers to your actor and defines virtual functions for the lifecycle of a state.
// FSMState.h
UCLASS(Abstract)
class UFSMState : public UObject {
GENERATED_BODY()
public:
virtual void OnEnterState() {}
virtual void OnUpdate(float DeltaTime) {}
virtual void OnExitState() {}
};
You then manage these states inside your AI Controller or Actor using a pointer to the "CurrentState." The "Robust" part of this pattern comes from how you trigger transitions. Instead of calling functions directly, you create a TransitionTo(TSubclassOf<UFSMState> NewStateClass) function:
- Cleanup: Call
OnExitState()on the current state. - Swap: Instantiate or switch the
CurrentStatepointer to the new class. - Initialize: Call
OnEnterState()on the new state.
Handling Transitions
The beauty of this approach is atomic transitions. By forcing all changes through a single TransitionTo method, you ensure that the OnExitState of your current state (where you might stop an animation or clear a timer) is never skipped. This prevents "state leaks," where logic from the previous state continues running incorrectly.
For state-specific logic, simply subclass UFSMState. For example, an UIdleState and an UAttackState can override OnUpdate to check for Blackboard conditions or distance checks, keeping your main Actor class clean and focused on high-level data management rather than deep branching logic.
Key Takeaway: By encapsulating transition logic in a base class method, you guarantee that entry and exit cleanup functions are always executed, preventing common bugs in complex state switching.