Debug SM, expose StateData to blueprint, make state duration optional

This commit is contained in:
Kevin Poretti 2023-07-25 22:25:01 -04:00
parent 3938ac54b5
commit 8420f654e8
5 changed files with 60 additions and 35 deletions

View File

@ -45,7 +45,7 @@ void UFFState::Update(float OneFrame, const FFFStateContext& InStateContext)
{ {
OnUpdate(OneFrame, InStateContext); OnUpdate(OneFrame, InStateContext);
if(InStateContext.Parent->GetTicksInState() >= StateDuration) if(bStateHasDuration && InStateContext.Parent->GetTicksInState() >= StateDuration)
{ {
Finish(InStateContext); Finish(InStateContext);
} }

View File

@ -49,6 +49,14 @@ public:
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="UFF State Properties") UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="UFF State Properties")
FName Name; FName Name;
/**
* True if this state has some duration where it should return to the entry state
* if this state is not cancelled out of by other means.
*/
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="UFF State Properties")
bool bStateHasDuration;
// TODO: this should only be editable if bStateHasDuration is true
/** /**
* How long this state will be active before finishing if this state is not cancelled out of * How long this state will be active before finishing if this state is not cancelled out of
* by other means. * by other means.

View File

@ -14,12 +14,15 @@
/** /**
* *
*/ */
UCLASS() UCLASS(BlueprintType)
class UNREALFIGHTINGFRAMEWORK_API UFFStateData : public UDataAsset class UNREALFIGHTINGFRAMEWORK_API UFFStateData : public UDataAsset
{ {
GENERATED_BODY() GENERATED_BODY()
public: public:
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
TSubclassOf<UFFState> EntryState;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly) UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
TArray<TSubclassOf<UFFState>> States; TArray<TSubclassOf<UFFState>> OtherStates;
}; };

View File

@ -5,18 +5,30 @@
// FF includes // FF includes
#include "FFState.h" #include "FFState.h"
#if !UE_BUILD_SHIPPING
static int32 StateMachineDebug = 0;
FAutoConsoleVariableRef CVARStateMachineDebug(TEXT("ff.StateMachine.ShowDebug"),
StateMachineDebug,
TEXT("Print state machine information for character"),
ECVF_Cheat);
#endif
UFFStateMachineComponent::UFFStateMachineComponent() UFFStateMachineComponent::UFFStateMachineComponent()
{ {
// Don't use Unreal's tick instead use a fixed tick // Don't use Unreal's tick instead use a fixed tick
PrimaryComponentTick.bCanEverTick = false; #if !UE_BUILD_SHIPPING
PrimaryComponentTick.bCanEverTick = true;
#else
PrimaryComponentTick.bCanEverTick = false;
#endif
} }
void UFFStateMachineComponent::Initialize() void UFFStateMachineComponent::Initialize(TSubclassOf<UFFState> EntryState, const TArray<TSubclassOf<UFFState>>& InitialStates)
{ {
UFFState* EntryStateInstance = AddState(EntryState); UFFState* EntryStateInstance = AddState(EntryState);
for(const TSubclassOf<UFFState>& CurrState : DefaultStates) for(const TSubclassOf<UFFState>& CurrState : InitialStates)
{ {
AddState(CurrState); AddState(CurrState);
} }
@ -134,7 +146,12 @@ void UFFStateMachineComponent::FixedTick(float OneFrame)
{ {
// CurrentState should never be null // CurrentState should never be null
// TODO: Should probably assert or whatever UE's equivalent is // TODO: Should probably assert or whatever UE's equivalent is
check(CurrentState); //check(CurrentState);
// TODO: yet another reason I want FULL CONTROL over when my game objects are created and initialized
if(!CurrentState)
{
return;
}
// Should we switch states? // Should we switch states?
UFFState* StateToTransitionTo = nullptr; UFFState* StateToTransitionTo = nullptr;
@ -161,16 +178,6 @@ void UFFStateMachineComponent::FixedTick(float OneFrame)
TicksInState++; TicksInState++;
CurrentState->Update(OneFrame, GetCurrentStateContext()); CurrentState->Update(OneFrame, GetCurrentStateContext());
} }
// Debug
}
void UFFStateMachineComponent::BeginPlay()
{
Super::BeginPlay();
Initialize();
} }
@ -185,7 +192,26 @@ UFFState* UFFStateMachineComponent::FindStateWithName(FName StateName)
} }
UE_LOG(LogTemp, Warning, UE_LOG(LogTemp, Warning,
TEXT("Could not find state in state machine with name %s on %s"), *StateName.ToString(), *Owner->GetName()); TEXT("Could not find state in state machine with name %s"), *StateName.ToString());
return nullptr; return nullptr;
} }
#if !UE_BUILD_SHIPPING
void UFFStateMachineComponent::TickComponent(float DeltaTime, ELevelTick TickType,
FActorComponentTickFunction* ThisTickFunction)
{
Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
// Debug
if(StateMachineDebug)
{
FString SMDebugString = "---State Machine Info---\n";
SMDebugString.Append(FString::Printf(TEXT("Current State: %s\n"), *CurrentState->Name.ToString()));
SMDebugString.Append(FString::Printf(TEXT("Current SubState Label: %s\n"), *CurrentSubStateLabel.ToString()));
SMDebugString.Append(FString::Printf(TEXT("Ticks In State: %lld\n"), TicksInState));
GEngine->AddOnScreenDebugMessage(-1, 0.0f, FColor::Green, SMDebugString);
}
}
#endif

View File

@ -29,7 +29,7 @@ public:
/** /**
* Creates and adds default states and enters the first state * Creates and adds default states and enters the first state
*/ */
void Initialize(); void Initialize(TSubclassOf<UFFState> EntryState, const TArray<TSubclassOf<UFFState>>& InitialStates);
/** /**
* Initializes pointers to what owns this state machine and what avatar this state represents. * Initializes pointers to what owns this state machine and what avatar this state represents.
@ -116,20 +116,6 @@ protected:
/** How many ticks have elapsed since the currently active state was entered */ /** How many ticks have elapsed since the currently active state was entered */
int64 TicksInState; int64 TicksInState;
/**
* The state the state machine will enter when the game begins and the state that will be
* transitioned into if a state finishes and no other states are eligible for transition.
*/
UPROPERTY(EditDefaultsOnly, Category="UFF|State Machine")
TSubclassOf<UFFState> EntryState;
/**
* States classes other than the entry state to create and add to this state machine when the
* game starts.
*/
UPROPERTY(EditDefaultsOnly, Category="UFF|State Machine")
TArray<TSubclassOf<UFFState>> DefaultStates;
/** Current active state for this state machine */ /** Current active state for this state machine */
UPROPERTY() UPROPERTY()
UFFState* CurrentState; UFFState* CurrentState;
@ -146,7 +132,9 @@ protected:
*/ */
UFFState* FindStateWithName(FName StateName); UFFState* FindStateWithName(FName StateName);
#if !UE_BUILD_SHIPPING
// UActorComponent interface // UActorComponent interface
virtual void BeginPlay() override; virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
// End of UActorComponent interface // End of UActorComponent interface
#endif
}; };