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;
switch (RequiredButtonState)
{
// TODO: should it be (PrevInput & RequiredButtons) == RequiredButtons or what we have now?
case EFFButtonState::BTNS_Pressed:
if(!(PrevInput & RequiredButtons | PrevDisable) &&
CurrInput & RequiredButtons & ~CurrDisable)

View File

@ -10,6 +10,43 @@
// UE includes
#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)
{
if(InStateContext.Avatar)
@ -54,43 +91,12 @@ void UFFState::Update(float OneFrame, 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;
}

View File

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

View File

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

View File

@ -62,17 +62,24 @@ public:
*/
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
*
* 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
*/
void SwitchToEntryState();
void GoToEntryState();
UFUNCTION(BlueprintPure)
FORCEINLINE int64 GetTicksInState() const;