UFSM: Finite State Machine

You should look in plugin classes and see how “conditional SetState()” works.

If you want to call SetState() that way you should setup a condition to do so once the door is fully open.

So SetState() have to be called in Tick() or OnAnyUpdateState()
I think what I am trying to do is to define a conditional state transition which would be executed when we are in a state to know if there is a state change.



 var fsm = new FiniteStateMachine<string>("closed", "open", "locked");
fsm.AddTransition("closed", "open", OPEN_COMMAND)    
.AddTransition("closed", "locked", LOCK_COMMAND, customTransition) // using a custom transition    
.AddTransition("locked", "closed", UNLOCK_COMMAND, () => user.HasKey()) // using a condition    
.AddTransition("open", "closed", CLOSE_COMMAND)    
.OnEnter(open, () => Debug.Log("The door is now open!"))    
OnExit(closed, HandleDoorIsNoLongerClosed);


but I understand if it is not the way to use the ufsm plugin.
thank you

@FaSDt1517 this plugin was built to support several different workflows (depending on team’s preferences)…

For the model you intend to use, you should create of sub-class of UStateMachineComponent and attach that subclass to your Actor.
I am going to work right now, but as soon I have some free minutes I post a C++ example for you to study.

@FaSDt1517

https://i.imgur.com/WhSPYMB.png

There’s four things to keep in mind doing things this way:

  • Transitions are UFunctions, you never call them manually.
  • Your transition functions must be named as follows: “From + StateName + To + NewStateName”.
  • You never call any SetState() functions, the custom component calls them when your transition function succeeds.
  • You usually do all the state work inside of your custom FSM component class, instead of in owner character class. [HR][/HR]
    Here’s an example Character Class + Custom FSM Component:

FSM_NativeCharacter_AutoFlowAPI.h:



#pragma once

#include "UFSM.h"
#include "GameFramework/Character.h"
#include "FSM_NativeCharacter_AutoFlowAPI.generated.h"


class UFSM_AutoFlowAPI;


UCLASS()
class UNREAL_FSM_API AFSM_NativeCharacter_AutoFlowAPI :  ACharacter
{
    GENERATED_BODY()

:
    // Sets default values for this character's properties
    AFSM_NativeCharacter_AutoFlowAPI();

    UPROPERTY()
    UFSM_AutoFlowAPI* StateMachine;

    UPROPERTY()
    float Energy = 0.0f;

protected:

    UFUNCTION() void OnBeginState(uint8 StateID, uint8 PreviousStateID, FName StateName, FSM_Transition Transition);
    UFUNCTION() void OnUpdateState(uint8 StateID, FName StateName, float StateTime);
    UFUNCTION() void OnExitState(uint8 StateID, FName StateName, FSM_Transition Transition);

};


FSM_NativeCharacter_AutoFlowAPI.cpp:



#include "FSM_NativeCharacter_AutoFlowAPI.h"
#include "FSM_AutoFlowAPI.h"


AFSM_NativeCharacter_AutoFlowAPI::AFSM_NativeCharacter_AutoFlowAPI()
{
    PrimaryActorTick.bCanEverTick = true;

    StateMachine = CreateDefaultSubobject<UFSM_AutoFlowAPI>(TEXT("StateMachine"));
    if (StateMachine->IsValidLowLevelFast()) {

        StateMachine->OnBegin.AddDynamic(this,&AFSM_NativeCharacter_AutoFlowAPI::OnBeginState);
        StateMachine->OnUpdate.AddDynamic(this,&AFSM_NativeCharacter_AutoFlowAPI::OnUpdateState);
        StateMachine->OnExit.AddDynamic(this,&AFSM_NativeCharacter_AutoFlowAPI::OnExitState);

    }
}


void AFSM_NativeCharacter_AutoFlowAPI::OnBeginState(uint8 StateID, uint8 PreviousStateID, FName StateName, FSM_Transition Transition)
{
    LOG_FSM(true,FString::Printf(TEXT("On Begin State::  %s"),*StateName.ToString()));
}

void AFSM_NativeCharacter_AutoFlowAPI::OnUpdateState(uint8 StateID, FName StateName, float StateTime)
{
    LOG_FSM(true,FString::Printf(TEXT("On Update State::  %s"),*StateName.ToString()));
}

void AFSM_NativeCharacter_AutoFlowAPI::OnExitState(uint8 StateID, FName StateName, FSM_Transition Transition)
{
    LOG_FSM(true,FString::Printf(TEXT("On Exit State::  %s"),*StateName.ToString()));
}


FSM_AutoFlowAPI.h:



#pragma once

#include "UFSM.h"
#include "FSM_AutoFlowAPI.generated.h"


class AFSM_NativeCharacter_AutoFlowAPI;


UCLASS()
class UNREAL_FSM_API UFSM_AutoFlowAPI :  UStateMachineComponent
{
    GENERATED_BODY()

:
    UFSM_AutoFlowAPI();


    UFUNCTION() void OnBeginIdle(const FSM_BeginEvent StateInfo);
    UFUNCTION() void OnUpdateIdle(const FSM_UpdateEvent StateInfo);
    UFUNCTION() void OnExitIdle(const FSM_ExitEvent StateInfo);

    UFUNCTION() void OnBeginRun(const FSM_BeginEvent StateInfo);
    UFUNCTION() void OnUpdateRun(const FSM_UpdateEvent StateInfo);
    UFUNCTION() void OnExitRun(const FSM_ExitEvent StateInfo);


    UFUNCTION() void FromIdleToRun(FSM_Transition &Condition);
    UFUNCTION() void FromRunToIdle(FSM_Transition &Condition);

};


FSM_AutoFlowAPI.cpp:



#include "FSM_AutoFlowAPI.h"
#include "UFSM_FunctionLibrary.h"
#include "Math/UnrealMathUtility.h"

#include "FSM_NativeCharacter_AutoFlowAPI.h"


UFSM_AutoFlowAPI::UFSM_AutoFlowAPI()
{
    PrimaryComponentTick.bStartWithTickEnabled = true;
    PrimaryComponentTick.bCanEverTick = true;
    bWantsInitializeComponent = true;
    bAutoActivate = true;

    BlueprintAutoFlowFSM = true;
    BlueprintAutoFlowTransitions = true;

    AddState(0,FName("Idle"));
    AddState(1,FName("Run"));
    AddState(2,FName("Jump"));

    StartupState = FName("Idle");
}



void UFSM_AutoFlowAPI::OnBeginIdle(const FSM_BeginEvent StateInfo)
{
    LOG_FSM(true,TEXT("On Begin Idle!"));
}

void UFSM_AutoFlowAPI::OnUpdateIdle(const FSM_UpdateEvent StateInfo)
{
    LOG_FSM(true,TEXT("On Update Idle!"));
}

void UFSM_AutoFlowAPI::OnExitIdle(const FSM_ExitEvent StateInfo)
{
    LOG_FSM(true,TEXT("On Exit Idle!"));
}


void UFSM_AutoFlowAPI::OnBeginRun(const FSM_BeginEvent StateInfo)
{
    LOG_FSM(true,TEXT("On Begin Run!"));
}

void UFSM_AutoFlowAPI::OnUpdateRun(const FSM_UpdateEvent StateInfo)
{
    LOG_FSM(true,TEXT("On Update Run!"));
}

void UFSM_AutoFlowAPI::OnExitRun(const FSM_ExitEvent StateInfo)
{
    LOG_FSM(true,TEXT("On Exit Run!"));
}


void UFSM_AutoFlowAPI::FromIdleToRun(FSM_Transition &Condition)
{
    if (AFSM_NativeCharacter_AutoFlowAPI* Owner = Cast<AFSM_NativeCharacter_AutoFlowAPI>(GetOwner())) {
        bool isIdle = FMath::IsNearlyEqual(Owner->GetVelocity().Size(),0.f,0.1f);
        bool isGrounded = Owner->CanJump();

        Condition = UFSMHelper::FSM_EvaluateTwoBools(isGrounded,isIdle);
    }
}

void UFSM_AutoFlowAPI::FromRunToIdle(FSM_Transition &Condition)
{
    bool timeout = (StateTime >= 5.f);

    if (AFSM_NativeCharacter_AutoFlowAPI* Owner = Cast<AFSM_NativeCharacter_AutoFlowAPI>(GetOwner())) {
        bool exausted = FMath::IsNearlyEqual(Owner->Energy,0.f,0.1f);
        bool stop = (timeout && exausted);

        Condition = UFSMHelper::FSM_EvaluateBool(stop);
    }
}


[HR][/HR]
Pay extra attention to state function signatures, They cannot deviate from that.
Transition params should be always be (FSM_Transition &Condition) and state params should always be (const FSM_xxxEvent StateInfo).

If you recreate example above and drop the *FSM_NativeCharacter_AutoFlowAPI *character inside a level, when playing it is going to enter “Run” state every 5 seconds then go back to “Idle” and start “Run” again… :

https://i.imgur.com/n0k3MGu.png

Thanks. I had a break and got back into it. I have now a complete swing door working in cpp with states transitioning as your example above (only checking owner for data values).
This is tidy.
Only “missing” extra feature would be to “visualize” the states graph. “Visualize” in the blueprint does nothing. It would be good to see the states and the transitions (even read-only. no transition redefinition). On click, it could open the function in BP if defined or c++. not sure if it should work like that or if it is not implemented.

Thanks!

Hello Bruno! I hope all is well with you, just writing because I’m migrating from version 1 to version 3 and there’s many game breaking changes (I’m happy to fix them by myself) I’m just confused on where to start appart from the example project. Do you have any videos or a changelog explaining what’s new and what do I have to do to use the new FSM version?

All the best.

Hello!
There is an updated demo project here for v3:

For C++ samples, there’s a few examples posted above in this forum.

I just came back to the Unreal engine, not used it for over a year, I finally got my project upgraded to 4.24 (was 4.17) however I am getting the error FSM Auto Flow, I remember this previously and I had to switch off this becuase I was using C++ components not blueprint to handle the states. I am using UFSM version 3 but I cannot find the auto flow option on the settings, did this change? thanks

It’s on your fsm details panel.
a member of the component now.

Sorry for being dumb but how do I get to the “fsm detail panel”?

myFSM->BlueprintAutoFlowFSM = false;

Thanks I used the BlueprintAutoFlowFSM property and set to false on all my FSM definitions…

I set this value on all class UFSM components, however I am still getting the log message

{FSM}:: ‘‘Blueprint Auto Flow FSM’’ is enabled; Trying to invoke ‘‘On Exit’’ for (Standing) State, but (OnExitStanding) function have not been found! → Exit: [Function /Script/UFSM.StateMachineComponent:Exit at (StateMachineComponent /Game/Maps/UEDPIE_0_TestLevel.TestLevel:PersistentLevel.BP_Player_C_0.Player Stance State Machine)]

m_FSM_StanceState->BlueprintAutoFlowFSM = false;

Not sure why this is happening?

Set the value in your class constructor or BeginPlay()… or PostInitProperties().
Try visual studio debugger to check if your class is actually using value = false;

Depends on how your project is setup, Unreal will serialize the property in your class and changing it in C++ won’t do anything.

That worked, the problem was that my VS 2019 was not setup correctly and was not vompiling the project… my bad sorry…

I am getting this in the log?

Exit: ]---------->(Standing) at (StateMachineComponent /Game/Maps/UEDPIE_0_TestLevel.TestLevel:PersistentLevel.BP_Player_C_0.Player Stance State Machine)

Hi, I bought this plugin a few years ago but just coming back to Unreal after developing my own FSM system in C#. I’m glad to see it’s still being updated so I’m going to be using it for my project (no C++ unfortunately). I’m a little disheartened to see the documentation still very lacking beyond this thread and the API reference but it is what it is I guess.

So I guess I’ll just need to ask some questions instead, but apologies if they have already been asked.

  1. I’m not currently needing a ton of complex use from my FSM although that might change in the future. But one thing that I will be doing a lot is playing an animation montage within a state (let’s say, PlayAnimation) and waiting for it to finish before switching states back again. I understand that if this was in an animation FSM I can just set the state when the transition ends, but since this is a montage and I want to play the montage from the OnBeingPlayAnimation, I have a variable set up that reads the montage length then, in the FSM event graph I’m doing a switch on the update and simply using a delay with this time before manually setting the state back to normal. This is pretty yucky to me and I can’t imagine it’s the preferred method, so is there some built in way I can do this? I can’t use a delay within the OnUpdatePlayAnimation, and honestly that’s still a bit dirty anyway.

  2. Would the general preferred method be to use both the FSM component as well as the AnimBP to control where the states go or try and keep it to the FSM component as much as possible for cleanliness?

  3. I would like to keep all my gameplay functionality contained within the states. So for example, when the user presses the jump button, if it’s in the normal state it will jump, but if it’s in a crouching state, it will stand (or whatever). I know I could get the current state and do a switch based on that, but that feels like it flies in the face of the FSM philosophy (moving away from enums and conditionals towards self contained code). However, we are only given begin, update, end and finish. How can I encapsulate more than that within a state such as events? This seems like a core piece of the puzzle to me to keeping state machines organised.

I will undoubtedly have some more questions as I go down this rabbit hole, but if you could give me some advice on the best way to set this up I’d appreciate it :slight_smile:

-edit- I’ve switched it so in the OnUpdatePlayAnimation I’m checking the animbp if any montage is playing and when set to false I’m going back to the normal state. Again, unsure if this is the best way but seems much better than using a delay.

@PlayingKarrde in a situation like this I prefere to have my AnimBP as a subclass of the AnimBP classes included with the FSM plugin, and on the FSM Component I setup “transition rule functions”…

I will try to explain quickly what you need to setup transition rule functions for a FSM Component (not the anim bp):
[HR][/HR]

  1. A enum to store states is good to have because then I don’t need to type enum names anywhere or memorize state IDs; So I create a enum BP for the states needed before working on the component, like this sample one:

[HR][/HR]
2) I setup the FSM Component to actually use the enum BP as state input data, and make sure that “auto flow” options are enabled. I create a FSM Component Blueprint (FSM asset) for this, I do not use the native FSM component. With that checked, I click the “+Functions” button on details panel of the component, it will create state functions:

[HR][/HR]
3) Transition rules are functions prefixed with a “<T>” on their category. The ones I don’t need later I just delete them:

[HR][/HR]
4) Transition functions will return a value to the c++ runtime of your FSM Component, depending on the value returned the component does the same thing an animation transition does, switches to target state; So you can use custom nodes included with the plugin to evaluate rules and dictate what a transition should return based on what you have just evaluated there. See some of the evaluation nodes here:

[HR][/HR]
5) So, you could setup a transition rule that will automatically quit your montage’s state and go back to ‘normal’ state as soon blend time is where you need, instead of using Delay nodes;
Something maybe like this:

[HR][/HR]
6) And because the AnimBP is child of the “FSM Anim” that is added with the plugin, and states on the FSM Component are input from an Enum BP… On Anim BP graphs it’s possible to also modify behavior checking what the FSM Component side is doing with a simple Switch on (enum) node, I use this setup quite a lot, something like this:

Thanks for the reply and detailed response. Making the anim bp a child of your anim bp is a great idea and will no doubt save me some headaches later. The conditional transitions are also great to know about.

How would you go about encapsulating functionality though? Basically what I’d like is to be able to have my states keep functionality for controls. So for example, in your blog post from a few years ago with the setting up a ladder example, you send the input axis to the FSM component so the states can read that as they like. I’d basically like something like that but for a button press. I don’t want to have conditionals within my states or within my character BP since that starts to defeat the point of an FSM in that it can get complicated fast. I also would prefer to not have to set a bool then unset it again, as that too is messy.

I’m sure what I’m asking is already possible but I can’t think of the correct way to go about it.

You can have hierarchical state machine node graphs (HSM) within FSM Component graphs. They are great for handling controller inputs.

​​​​​​Latest demo project have an working example of them in use on character blueprint. You can find link to demo project on plugin’s marketplace page.

There’s a little introductory info about them here:
https://forums.unrealengine.com/unreal-engine/marketplace/88276-ufsm-finite-state-machine?p=1717741#post1717741

OK I’m still trying to get my head around this. In your example you have two example character controllers doing the same thing, but one is using an FSM and the other an RSM. I’m not really understanding how they can be used together (and why your example doesn’t do so?). Should I be firing into the control RSM (using your example’s terminology) in the FSM’s begin state (say, Normal) and firing into the exit node on the end state? The way you have it seems counter-intuitive to me - two different systems not working together at all.

I’m clearly failing to understand rather than it being a failing of your system (documentation!?). I like the idea of encapsulating states in state actions and plugging them in. But how the RSM fits into the state machine system I don’t see still.

-edit- Just for clarity, here’s what I want to do:

  1. Have an input, say, Jump fire an event
  2. Each state has the ability to listen for that event and when it happens do some logic based on that
  3. None of this I want to happen with a case statement or any kind of bool checking - if the Normal state is active then the logic tied to the jump action fires, if I am in the crouch state I want the jump action specific to the crouch state to fire. Neither state needs to know anything about the other state and there shouldn’t be any branches or switches anywhere.