UFSM: Finite State Machine

Hey Bruno, I wanted to apologize for my last couple posts. I was frustrated with my project and because of that lashed out at you in an unprofessional way. I also now realize that I don’t have the skill with C++ necessary to successfully use this plugin. I’ve since tried using UFSM with blueprints and have had a much better time getting things done. :slight_smile:

Sorry again for the attitude of my previous posts, and thank you for creating an extremely useful plugin.

Nothing to apologize for; I know very well things can become a headache quickly in C++.
I ***want ***to make more learning material, I just need to find a way to “create” the free time I need to create some tutorials when coding C++ is the focus.

Submitted latest release for UE4.18 update; Epic hopefully releases new files shortly after!

So, I’ve defined a Enum in C++ but when I go to use it in the Finite State Machine component in editor, it doesn’t appear in the list. Is this a limitation? I know the C++ enum is available in blueprints because I can define an ordinary variable using it in blueprints. What’s up?

Hi Bruno, I’ve just bought UFSM as I feel it will help tremendously with my project, but as the documentation is out of date I’ve been reading through the forum and am getting confused about the workflow you intend with this plugin.

Here is how I understand it:

UFSM_workflow.png

So if I am correct, the original method is to have your character bp take the input and drive the motion of your character. The anim bp would only listen to the character bp in order to update the visual animation (for the sake of simplicity lets assume no root motion).

However, with your plugin, what I’m understanding is you intend the logic and all motion to actually come from your FSM anim bp (since that’s where the visual state machine lives) and it’s simply listening to the character bp to get the input. The extra step is the FSM bp which is just there for some extra logic (?) on state changes?

Clearly I’m pretty confused so if you could clear up the intended workflow for the plugin I’d really appreciate it.

Also, I’m curious why the FSM BP generates functions rather than events. Would it not make more sense for them to be events so we can get access to the tick (for On Update)?

Thanks.

Your enum is meant to be an UEnum asset.
In case of enum defined in C++, Unreal won’t show them in the drop-down list, this is on Unreal’s limitations not enforced by me.

You don’t really need to use AnimBP States, unless you have very complex behavior going on such as a parkour game. The syncing to AnimBP I’ve added for a Stealth action game and a Skateboarding game.

The AnimBP in this case would be the “lead”, you can’t sync AnimBP States from your FSM Component, but you can sync States from AnimBP to your FSM Component.
So, no; the “listener” would be the other way around.
This is meant to allow developer execute code directly reacting to AnimBP State changes without dealing with a clutter of Anim Notifies to setup.

Your AnimBP you use as usual, no workflow differences there.
Again, what the plugin does is provide you a way to efficiently execute functions based AnimBP State changes, directly; but then again, this is for specific project design patterns, yoy can use FSM Component Blueprints without touching any AnimBP as well.

Events and functions are basically the same thing.
Your OnUpdateXX is being called by your Tick event already (in the C++ side of the plugin), so wouldn’t make sense to allow call Tick -> OnUpdateXX -> Tick again.

The OnEnterXX and OnExitXX functions are also called by Events as well, you can see the root events in a FSM Component details panel when you open an Actor Blueprint that have a FSM Component attached.

Hello, Just integrating UFSM into my C++ project.

Any advice on correct way to control which states can follow the current state … it seems currently that you can set any state at any time, but that obviously isnt necessarily correct.

Thanks in advance

In CPP the flow is pretty much up to you control conditions; I didn’t want to create ‘garbage’ objects to lock condition flow like in the AnimGraph (mainly because we already can use the AnimGraph for that).

Btw, as a basic sample for you to have a starting point:
For AI Character code I’m using a lot of conditions based on the time a certain state has being running, for example this just iterates existing states for controller debugging in the project:



void AFSM_NativeCharacter::Tick(float DeltaTime)
{
    Super::Tick(DeltaTime);

    FSM_Transition Trans;
    if (StateMachine->GetTime() > 4 && (StateMachine->GetCurrentStateID() < StateMachine->GetLastStateID())) {
        StateMachine->SetStateID(StateMachine->GetCurrentStateID()+1,Trans);
    } else if (StateMachine->GetTime() > 4) {
        StateMachine->SetStateID(0,Trans);
    }
}


But most the time I only change states when reacting to player input, trigger events, AI conditions or animation state changes.

Thanks very much will add some conditional logic myself

@SolarVelocity
You’ll probably want to use the conditional functions in C++ instead of the basic ones as well.
The functions for these nodes:


Are in the FSM Component declared this way:



    void SetState_Conditional(const FName Name, FSM_Transition Condition, FSM_Transition &Transition);

    void SetStateID_Conditional(const uint8 ID, FSM_Transition Condition, FSM_Transition &Transition);

    void SetStateValue_Conditional(const FSM_State &Value, FSM_Transition Condition, FSM_Transition &Transition);


Whatever the result is after you call one of these functions, the ‘FSM_Transition’ struct constains the result info after evaluating your data condition.
The conditional checking node functions are declared inside the UFSM/Source/UFSM//UFSMFunctionLibrary.h file.

So to call one of them from C++ could be something like:



FSM_Transition Trans;

StateMachine->*SetStateID_Conditional*(TEnumAsByte<EMovementStates::Sneaky>,*FSM_EvaluateBool(HasSneakyPants)*,Trans);

switch (Trans) {
    case FSM_Transition::Succeeded:          // The plugin runtime will return this if HasSneakyPants is true!
          // SneakyPants is thing now, let's show your suppah moves!
          DoAwesomeCQCFollowedByRoundHouseKickMove(); //!!
          break;
   case FSM_Transition::Aborted:          // The plugin runtime will return this if *HasSneakyPants *aint true.
          // Bummer. no fun this time...
          SitInACornerThenCry();
          break;
}


Doing that way, the State ID of Sneaky enum will never be set and the FSM Component will never leave current State unless 'HasSneakyPants’ is set to true somewhere in the game ^^

I will submit version 1.7.0 (Unreal 4.18++) for review soon :slight_smile:

This update adds several new Nodes of “Set State” function, for productivity reasons, as requested.
New Nodes can execute ‘callback’ Events and some can be executed as a timed asynchronous task:

The Async Nodes of Set State function can only be executed inside of a Blueprint Graph from a FSM Component, because many tiny little reasons;
They won’t be usable within your Character BP for example, but you can call them just fine within your FSM’s Blueprint Graph:

[HR][/HR]

You can easily create and attach Custom Events to callback pins by click-dragging from them on BP Graph (Blueprints are awesome):

[HR][/HR]

Improved the internals of “Auto Flow” system and Editor’s “Generate +Functions” button.

Now Plugin’s runtime is capable of invoking your State functions with a “State Info” struct parameter. (if ‘Auto-Flow’ Project Setting is enabled)
The struct is fed automatically by the runtime and you get, inside exec functions, information such as current and previous State ID without having to call additional nodes for that;

Execution functions that are automatically created by the “Generate +Functions” (from enum that you set in Details Panel) have now the output pin “State Info” auto inserted on function’s main node for you:

“State Info” can tell your ‘On Exit’ exec function which is next State to be set and what is its name, *before *‘On Exit’ has actually broadcasted its events and finished its execution cycle:

Your current exec functions without “State Info” will still work with Auto Flow setting so no worries there, but if you wish to update them the easiest way is to rename your current ones, regenerate exec functions then copy nodes from old Graph to the new one with “State Info” already implemented:

If, for whatever reason, you have Auto Flow disabled it’s still possible to reproduce the same “State Info” but you’ll have to manually setup your Graph for each of your On XXX functions and create the Info manually:

1.7 for UE4.18+ is now live on Marketplace :slight_smile:

Great update, much appreciated!

Quick question: is there some way to set up an interping transition value and a rule or a timer when it moves from one state to another, or should the transition be a state itself? This would be useful for feeding into animation blueprints and things like that.

One thing I thought about doing was to add “transition” state and have separate “old state” and “new state” values, then specific events to call for their transition rates.

So for example if I was doing AI and I had a character charging it could go: “charging -> transition -> stop”, where the transition from charge to stop would feed a bunch of things like deceleration and animation blend weights. Then inside the logic for the transition I could take into account if there was anything in front of the character or not and stop faster or slower as needed. The only requirement is that it needs to tick and interp away some values while being able to do custom environmental queries.

So I guess I’m asking does any facility for this exist already or is there a particular way you’d set it up? I have a rough layout but I’m sure you have a better understanding of it than me. :slight_smile:

The thing you think of doing might work pretty well; Internally, in the Animation Graphs, “transitions” are states too. They are just “presented” differently to the Blueprint user.
Btw, did you try to use one of the “Set State Async” nodes for this ?!

Currently none of them return the actual value of seconds they are waiting, but those only change State after its Timeline has completed evaluating its “Wait For Seconds” input.
I could expose that timeline to the Animation Graph as well, right now the float is private to the Async node alone.

Edit: “Async” nodes can be seen in this screenshot:

Update with support for Unreal Engine 4.19 have been submitted for review.

Hi Bruno, Thanks for making this, once working, it should solve some implementation problems I was having for a game I’m making.

I’m using 4.19 built from source from git.

My generate function’s button doesn’t seem to do anything.
Enabling Debug on the FSM component shows me a bunch of warnings about the functions not being found.

Also, My enumerator just seems to be detached/different than the enumerator being output by the anim bp.

When playing with debug on, the state that is being output is different than the state defined in my enumerator. I’ve read the wiki article multiple times and can’t seen to find much info on if we are just meant to make our own enumerator in blueprint, define it in c++, or if it gets generated from our anim bp or something like that?

If the button to generate functions doesn’t work on 4.19 that means you’re not using latest plugin version downloaded from Launcher.
4.19 only works with latest plugin release, EpicGames changed too many things on 4.19 and older code won’t work if you simply recompiled DLLs instead of downloading new plugin source.

As far as generating the functions, I can get away without. My main concern/issue at the moment is the enumeration difference between what is output by the anim bp’s state machine, and what my enumerator is.

I downloaded the 4.19 launcher version and then installed to engine via the launcher for 4.19 and then copied the plugin directory from the 4.19 engine/plugins/marketplace to my source built dir.

I did just attempt to recopy the 4.19 launcher plugin to my source built directory and it did want to recompile again.