Move state macros to plugin and make CanTransition virtual function

This commit is contained in:
Kevin Poretti 2023-07-29 21:18:34 -04:00
parent 8420f654e8
commit e032ddaaa5
6 changed files with 70 additions and 42 deletions

Binary file not shown.

View File

@ -28,6 +28,7 @@ bool UFFInputBufferComponent::CheckInputSequence(const FFFInputSequence& InputSe
int32 CurrDisable = InputBuffer[InpIdx].DisabledButtons; int32 CurrDisable = InputBuffer[InpIdx].DisabledButtons;
switch (RequiredButtonState) switch (RequiredButtonState)
{ {
// TODO: should it be (PrevInput & RequiredButtons) == RequiredButtons or what we have now?
case EFFButtonState::BTNS_Pressed: case EFFButtonState::BTNS_Pressed:
if(!(PrevInput & RequiredButtons | PrevDisable) && if(!(PrevInput & RequiredButtons | PrevDisable) &&
CurrInput & RequiredButtons & ~CurrDisable) CurrInput & RequiredButtons & ~CurrDisable)

View File

@ -10,6 +10,43 @@
// UE includes // UE includes
#include "Components/SkeletalMeshComponent.h" #include "Components/SkeletalMeshComponent.h"
bool UFFState::CanTransition(const FFFStateContext& InStateContext)
{
/**
* Check to see if avatar implements StateAvatarInterface
* if so then
* Check if the avatar is in the correct stance to perform this action
* Check if the state is enabled
* Check that all state entry conditions are met if there are any
*
* Check to see if the owner implements the StateOwnerInterface
* Check input conditions if there are any
*
* If all state entry conditions are good and at least one input condition is good then we can transition
* so return true otherwise return false
*/
IFFStateAvatarInterface* SAI = Cast<IFFStateAvatarInterface>(InStateContext.Avatar);
if(SAI)
{
if(!(SAI->CheckStance(StanceRequired) && SAI->CheckStateEnabled(StateType) && SAI->CheckStateEntryConditions(EntryConditions)))
{
return false;
}
}
IFFStateOwnerInterface* SOI = Cast<IFFStateOwnerInterface>(InStateContext.Owner);
if(SOI)
{
if(!SOI->CheckInputSequences(InputSequences))
{
return false;
}
}
return OnCanTransition(InStateContext);
}
void UFFState::Enter(const FFFStateContext& InStateContext) void UFFState::Enter(const FFFStateContext& InStateContext)
{ {
if(InStateContext.Avatar) if(InStateContext.Avatar)
@ -54,43 +91,12 @@ void UFFState::Update(float OneFrame, const FFFStateContext& InStateContext)
void UFFState::Finish(const FFFStateContext& InStateContext) void UFFState::Finish(const FFFStateContext& InStateContext)
{ {
InStateContext.Parent->SwitchToEntryState(); InStateContext.Parent->GoToEntryState();
} }
bool UFFState::CanTransition_Implementation(const FFFStateContext& InStateContext) bool UFFState::OnCanTransition_Implementation(const FFFStateContext& InStateContext)
{ {
/**
* Check to see if avatar implements StateAvatarInterface
* if so then
* Check if the avatar is in the correct stance to perform this action
* Check if the state is enabled
* Check that all state entry conditions are met if there are any
*
* Check to see if the owner implements the StateOwnerInterface
* Check input conditions if there are any
*
* If all state entry conditions are good and at least one input condition is good then we can transition
* so return true otherwise return false
*/
IFFStateAvatarInterface* SAI = Cast<IFFStateAvatarInterface>(InStateContext.Avatar);
if(SAI)
{
if(!(SAI->CheckStance(StanceRequired) && SAI->CheckStateEnabled(StateType) && SAI->CheckStateEntryConditions(EntryConditions)))
{
return false;
}
}
IFFStateOwnerInterface* SOI = Cast<IFFStateOwnerInterface>(InStateContext.Owner);
if(SOI)
{
if(!SOI->CheckInputSequences(InputSequences))
{
return false;
}
}
return true; return true;
} }

View File

@ -109,8 +109,7 @@ public:
* all state entry conditions were met AND * all state entry conditions were met AND
* at least one input sequence is present in the Owner's input buffer * at least one input sequence is present in the Owner's input buffer
*/ */
UFUNCTION(BlueprintNativeEvent, Category="UFF|State") virtual bool CanTransition(const FFFStateContext& InStateContext);
bool CanTransition(const FFFStateContext& InStateContext);
/** /**
* Called whenever this state is transitioned into. * Called whenever this state is transitioned into.
@ -151,6 +150,12 @@ public:
UFUNCTION(BlueprintCallable) UFUNCTION(BlueprintCallable)
virtual void Finish(const FFFStateContext& InStateContext); virtual void Finish(const FFFStateContext& InStateContext);
/**
* Blueprint hook for overriding the CanTransition logic
*/
UFUNCTION(BlueprintNativeEvent, Category="UFF|State|Events")
bool OnCanTransition(const FFFStateContext& InStateContext);
/** /**
* Blueprint hook for whenever this state is transitioned into * Blueprint hook for whenever this state is transitioned into
*/ */

View File

@ -85,7 +85,16 @@ void UFFStateMachineComponent::RemoveState(FName StateToRemove)
UE_LOG(LogTemp, Error, TEXT("UFFStateMachineComponent::RemoveState is not yet implemented")); UE_LOG(LogTemp, Error, TEXT("UFFStateMachineComponent::RemoveState is not yet implemented"));
} }
void UFFStateMachineComponent::SwitchStates(UFFState* NewState) void UFFStateMachineComponent::GoToState(FName NewStateName)
{
UFFState* NewState = FindStateWithName(NewStateName);
if(NewState)
{
GoToState(NewState);
}
}
void UFFStateMachineComponent::GoToState(UFFState* NewState)
{ {
check(CurrentState); check(CurrentState);
check(NewState); check(NewState);
@ -97,12 +106,12 @@ void UFFStateMachineComponent::SwitchStates(UFFState* NewState)
CurrentSubStateLabel = NAME_None; CurrentSubStateLabel = NAME_None;
} }
void UFFStateMachineComponent::SwitchToEntryState() void UFFStateMachineComponent::GoToEntryState()
{ {
// can't have an entry state if there are no states // can't have an entry state if there are no states
check(States.Num() > 0); check(States.Num() > 0);
SwitchStates(States[0]); GoToState(States[0]);
} }
@ -170,7 +179,7 @@ void UFFStateMachineComponent::FixedTick(float OneFrame)
if(StateToTransitionTo && if(StateToTransitionTo &&
(CurrentState->Name != StateToTransitionTo->Name || StateToTransitionTo->bCanTransitionToSelf)) (CurrentState->Name != StateToTransitionTo->Name || StateToTransitionTo->bCanTransitionToSelf))
{ {
SwitchStates(StateToTransitionTo); GoToState(StateToTransitionTo);
} }
else else
{ {

View File

@ -62,19 +62,26 @@ public:
*/ */
void RemoveState(FName StateToRemove); void RemoveState(FName StateToRemove);
/**
* Transitions from CurrentState to the new state with the name passed to this function
*
* Triggers the Exit callback on the CurrentState and the Enter callback on the new state
*/
void GoToState(FName NewStateName);
/** /**
* Transitions from CurrentState to the new state passed to this function * Transitions from CurrentState to the new state passed to this function
* *
* Triggers the Exit callback on the CurrentState and the Enter callback on the new state * Triggers the Exit callback on the CurrentState and the Enter callback on the new state
*/ */
void SwitchStates(UFFState* NewState); void GoToState(UFFState* NewState);
/** /**
* Transitions from CurrentState to the default entry state * Transitions from CurrentState to the default entry state
*/ */
void SwitchToEntryState(); void GoToEntryState();
UFUNCTION(BlueprintPure) UFUNCTION(BlueprintPure)
FORCEINLINE int64 GetTicksInState() const; FORCEINLINE int64 GetTicksInState() const;
/** /**