Example of how to initialize an FSM Component in C++ using the new API from UFSM 1.6.0 without losing your Dynamic Bindings after the Component have been initialized:
A Simple Character .H:
#pragma once
#include "UFSM.h"
#include "GameFramework/Character.h"
#include "FSM_NativeCharacter.generated.h"
UCLASS()
class MYGAMEAPI AFSM_NativeCharacter : ACharacter, IFSMInterface
{
GENERATED_BODY()
:
// Sets default values for this character's properties
AFSM_NativeCharacter();
UPROPERTY()
UStateMachineComponent* StateMachine;
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
:
// Called every frame
virtual void Tick(float DeltaTime) override;
// Called to bind functionality to input
virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
UFUNCTION()
void BindBeginIdle();
UFUNCTION()
void BindUpdateIdle();
UFUNCTION()
void BindExitIdle();
:
/// FSM: Initialization Interface.
UFUNCTION(Category = "FSM", BlueprintNativeEvent, BlueprintCallable, meta = (DisplayName = "FSM: On Initialized", Keywords = "FSM Initialization Interface"))
void OnInitializedFSM(const UStateMachineComponent* Context);
//
/// FSM: On Any 'On Begin' Event.
UFUNCTION(Category = "FSM", BlueprintNativeEvent, BlueprintCallable, meta = (DisplayName = "FSM: On Any Begin", Keywords = "FSM Begin Event"))
void OnAnyBeginState(const UStateMachineComponent* Context, const FName WithStateName, const uint8 WithStateID, const uint8 WithPrevious);
//
/// FSM: On Any 'On Update' Event.
UFUNCTION(Category = "FSM", BlueprintNativeEvent, BlueprintCallable, meta = (DisplayName = "FSM: On Any Update", Keywords = "FSM Update Event"))
void OnAnyUpdateState(const UStateMachineComponent* Context, const FName WithStateName, const uint8 WithStateID, const float WithStateTime);
//
/// FSM: On Any 'On Exit' Event.
UFUNCTION(Category = "FSM", BlueprintNativeEvent, BlueprintCallable, meta = (DisplayName = "FSM: On Any Exit", Keywords = "FSM Exit Event"))
void OnAnyExitState(const UStateMachineComponent* Context, const FName WithStateName, const uint8 WithStateID);
};
A Simple Character .CPP:
#include "FSM_NativeCharacter.h"
#include "Unreal_FSM.h"
AFSM_NativeCharacter::AFSM_NativeCharacter()
{
PrimaryActorTick.bCanEverTick = true;
StateMachine = CreateDefaultSubobject<UStateMachineComponent>(TEXT("StateMachine"));
if (StateMachine->IsValidLowLevelFast()) {
StateMachine->AddState(0,FName("Idle"));
StateMachine->AddState(1,FName("Stand"));
StateMachine->AddState(2,FName("Run"));
StateMachine->AddState(3,FName("Push"));
StateMachine->SetActive(true,true);
StateMachine->bAutoActivate = true;
StateMachine->Debug = true;
}
}
void AFSM_NativeCharacter::BeginPlay()
{
Super::BeginPlay();
FSM_Transition Trans;
StateMachine->SetStateID(0,Trans);
}
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);
}
}
void AFSM_NativeCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
Super::SetupPlayerInputComponent(PlayerInputComponent);
}
void AFSM_NativeCharacter::OnInitializedFSM_Implementation(const UStateMachineComponent* Context)
{
if (Context != StateMachine) {return;}
//
StateMachine->GetState(0)->OnBeginState.AddDynamic(this,&AFSM_NativeCharacter::BindBeginIdle);
StateMachine->GetState(0)->OnUpdateState.AddDynamic(this,&AFSM_NativeCharacter::BindUpdateIdle);
StateMachine->GetState(0)->OnExitState.AddDynamic(this,&AFSM_NativeCharacter::BindExitIdle);
}
void AFSM_NativeCharacter::OnAnyBeginState_Implementation(const UStateMachineComponent* Context, const FName WithStateName, const uint8 WithStateID, const uint8 WithPrevious) {/*...*/}
void AFSM_NativeCharacter::OnAnyUpdateState_Implementation(const UStateMachineComponent* Context, const FName WithStateName, const uint8 WithStateID, const float WithStateTime) {/*...*/}
void AFSM_NativeCharacter::OnAnyExitState_Implementation(const UStateMachineComponent* Context, const FName WithStateName, const uint8 WithStateID) {/*...*/}
void AFSM_NativeCharacter::BindBeginIdle() {
UE_LOG(LogTemp,Warning,TEXT("{FSM}:: %s"),TEXT("BINDED Begin!"));
}
void AFSM_NativeCharacter::BindUpdateIdle() {
UE_LOG(LogTemp,Warning,TEXT("{FSM}:: %s"),TEXT("BINDED Update!"));
}
void AFSM_NativeCharacter::BindExitIdle() {
UE_LOG(LogTemp,Warning,TEXT("{FSM}:: %s"),TEXT("BINDED Exit!"));
}
Making use of “IFSMInterface”, and its “OnInitializedFSM” Event, this way it’s possible to keep alive your C++ State Bindings even after someone have made changes to States on the Blueprint Component inherited from your C++ base class.