Expose state context members to blueprint and add Finish function to state
This commit is contained in:
parent
c652716895
commit
3938ac54b5
@ -82,7 +82,7 @@ struct FFFInputSequence
|
||||
}
|
||||
};
|
||||
|
||||
UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
|
||||
UCLASS( ClassGroup=(UnrealFightingFramework), meta=(BlueprintSpawnableComponent) )
|
||||
class UNREALFIGHTINGFRAMEWORK_API UFFInputBufferComponent : public UActorComponent
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
@ -44,6 +44,17 @@ void UFFState::Exit(const FFFStateContext& InStateContext)
|
||||
void UFFState::Update(float OneFrame, const FFFStateContext& InStateContext)
|
||||
{
|
||||
OnUpdate(OneFrame, InStateContext);
|
||||
|
||||
if(InStateContext.Parent->GetTicksInState() >= StateDuration)
|
||||
{
|
||||
Finish(InStateContext);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void UFFState::Finish(const FFFStateContext& InStateContext)
|
||||
{
|
||||
InStateContext.Parent->SwitchToEntryState();
|
||||
}
|
||||
|
||||
|
||||
@ -84,16 +95,6 @@ bool UFFState::CanTransition_Implementation(const FFFStateContext& InStateContex
|
||||
}
|
||||
|
||||
|
||||
void UFFState::GotoSubState(FName InSubStateLabel)
|
||||
{
|
||||
UFFStateMachineComponent* SMC = Cast<UFFStateMachineComponent>(GetOuter());
|
||||
if(SMC)
|
||||
{
|
||||
SMC->SetSubStateLabel(InSubStateLabel);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
UWorld* UFFState::GetWorld() const
|
||||
{
|
||||
UFFStateMachineComponent* SMC = Cast<UFFStateMachineComponent>(GetOuter());
|
||||
|
@ -17,21 +17,21 @@ struct FFFStateContext
|
||||
GENERATED_BODY()
|
||||
|
||||
/** Actor that owns the avatar. Typically a player controller. */
|
||||
UPROPERTY(BlueprintReadOnly)
|
||||
AActor* Owner;
|
||||
|
||||
/**
|
||||
* Actor that represents the player's avatar or an object associated with the player's avatar.
|
||||
* This is typically a character or a weapon.
|
||||
*/
|
||||
UPROPERTY(BlueprintReadOnly)
|
||||
AActor* Avatar;
|
||||
|
||||
/**
|
||||
* Parent state machine that controls this state
|
||||
*/
|
||||
const class UFFStateMachineComponent* Parent;
|
||||
|
||||
/** The number of ticks that have elapsed since this state was entered into */
|
||||
int64 TicksInState;
|
||||
UPROPERTY(BlueprintReadOnly)
|
||||
class UFFStateMachineComponent* Parent;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -95,8 +95,6 @@ public:
|
||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="UFF State Properties")
|
||||
UAnimMontage* MontageToPlay;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns true if Avatar's is in the correct stance AND
|
||||
* the state type is enabled (or the state can be hit or whiff cancelled from the current state) AND
|
||||
@ -106,12 +104,6 @@ public:
|
||||
UFUNCTION(BlueprintNativeEvent, Category="UFF|State")
|
||||
bool CanTransition(const FFFStateContext& InStateContext);
|
||||
|
||||
/**
|
||||
* Sets the current SubState label on the state machine that controls this
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category="UFF|State")
|
||||
void GotoSubState(FName InSubStateLabel);
|
||||
|
||||
/**
|
||||
* Called whenever this state is transitioned into.
|
||||
*
|
||||
@ -135,6 +127,22 @@ public:
|
||||
*/
|
||||
virtual void Update(float OneFrame, const FFFStateContext& InStateContext);
|
||||
|
||||
/**
|
||||
* Called when you want to exit from this state but no eligible transitions exist to other states,
|
||||
* usually due to a lack of player input.
|
||||
*
|
||||
* By default this will transition to the owning state machine's entry state, which is usually
|
||||
* an idle state.
|
||||
*
|
||||
* This function will get called automatically when the ticks in this state reaches the
|
||||
* threshold set by the StateDuration member, but you can call it whenever you wish to return
|
||||
* to the entry state.
|
||||
*
|
||||
* @param InStateContext
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable)
|
||||
virtual void Finish(const FFFStateContext& InStateContext);
|
||||
|
||||
/**
|
||||
* Blueprint hook for whenever this state is transitioned into
|
||||
*/
|
||||
|
@ -14,15 +14,18 @@ UFFStateMachineComponent::UFFStateMachineComponent()
|
||||
|
||||
void UFFStateMachineComponent::Initialize()
|
||||
{
|
||||
UFFState* EntryStateInstance = AddState(EntryState);
|
||||
|
||||
for(const TSubclassOf<UFFState>& CurrState : DefaultStates)
|
||||
{
|
||||
UFFState* TempState = AddState(CurrState);
|
||||
if(!CurrentState) // first state to be created is the entry into this state machine
|
||||
{
|
||||
CurrentState = TempState;
|
||||
CurrentState->Enter(GetCurrentStateContext());
|
||||
}
|
||||
AddState(CurrState);
|
||||
}
|
||||
|
||||
// need an entry state or something went seriously wrong
|
||||
check(EntryStateInstance);
|
||||
|
||||
CurrentState = EntryStateInstance;
|
||||
CurrentState->Enter(GetCurrentStateContext());
|
||||
}
|
||||
|
||||
|
||||
@ -38,10 +41,20 @@ UFFState* UFFStateMachineComponent::AddState(TSubclassOf<UFFState> StateClassToA
|
||||
UFFState* TempState = NewObject<UFFState>(this, StateClassToAdd);
|
||||
if(TempState)
|
||||
{
|
||||
States.Add(TempState);
|
||||
return TempState;
|
||||
if(!FindStateWithName(TempState->Name))
|
||||
{
|
||||
States.Add(TempState);
|
||||
return TempState;
|
||||
}
|
||||
|
||||
UE_LOG(LogTemp, Error, TEXT("State with name %s already exists in state machine for %s"),
|
||||
*TempState->Name.ToString(), *GetOwner()->GetFName().ToString());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
UE_LOG(LogTemp, Error, TEXT("Could not create instance of state class %s"),
|
||||
*StateClassToAdd.GetDefaultObject()->Name.ToString());
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -72,6 +85,20 @@ void UFFStateMachineComponent::SwitchStates(UFFState* NewState)
|
||||
CurrentSubStateLabel = NAME_None;
|
||||
}
|
||||
|
||||
void UFFStateMachineComponent::SwitchToEntryState()
|
||||
{
|
||||
// can't have an entry state if there are no states
|
||||
check(States.Num() > 0);
|
||||
|
||||
SwitchStates(States[0]);
|
||||
}
|
||||
|
||||
|
||||
int64 UFFStateMachineComponent::GetTicksInState() const
|
||||
{
|
||||
return TicksInState;
|
||||
}
|
||||
|
||||
|
||||
FName UFFStateMachineComponent::GetCurrentStateName() const
|
||||
{
|
||||
@ -81,14 +108,9 @@ FName UFFStateMachineComponent::GetCurrentStateName() const
|
||||
}
|
||||
|
||||
|
||||
FFFStateContext UFFStateMachineComponent::GetCurrentStateContext() const
|
||||
FName UFFStateMachineComponent::GetCurrentSubStateLabel() const
|
||||
{
|
||||
FFFStateContext CurrStateContext;
|
||||
CurrStateContext.Owner = Owner;
|
||||
CurrStateContext.Avatar = Avatar;
|
||||
CurrStateContext.Parent = this;
|
||||
CurrStateContext.TicksInState = TicksInState;
|
||||
return CurrStateContext;
|
||||
return CurrentSubStateLabel;
|
||||
}
|
||||
|
||||
|
||||
@ -98,28 +120,13 @@ void UFFStateMachineComponent::SetSubStateLabel(FName InSubStateLabel)
|
||||
}
|
||||
|
||||
|
||||
UFFState* UFFStateMachineComponent::FindStateWithName(FName StateName)
|
||||
FFFStateContext UFFStateMachineComponent::GetCurrentStateContext()
|
||||
{
|
||||
for (UFFState* CurrState : States)
|
||||
{
|
||||
if(CurrState->Name == StateName)
|
||||
{
|
||||
return CurrState;
|
||||
}
|
||||
}
|
||||
|
||||
UE_LOG(LogTemp, Warning,
|
||||
TEXT("Could not find state in state machine with name %s on %s"), *StateName.ToString(), *Owner->GetName());
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
void UFFStateMachineComponent::BeginPlay()
|
||||
{
|
||||
Super::BeginPlay();
|
||||
|
||||
Initialize();
|
||||
FFFStateContext CurrStateContext;
|
||||
CurrStateContext.Owner = Owner;
|
||||
CurrStateContext.Avatar = Avatar;
|
||||
CurrStateContext.Parent = this;
|
||||
return CurrStateContext;
|
||||
}
|
||||
|
||||
|
||||
@ -158,3 +165,27 @@ void UFFStateMachineComponent::FixedTick(float OneFrame)
|
||||
// Debug
|
||||
}
|
||||
|
||||
|
||||
void UFFStateMachineComponent::BeginPlay()
|
||||
{
|
||||
Super::BeginPlay();
|
||||
|
||||
Initialize();
|
||||
}
|
||||
|
||||
|
||||
UFFState* UFFStateMachineComponent::FindStateWithName(FName StateName)
|
||||
{
|
||||
for (UFFState* CurrState : States)
|
||||
{
|
||||
if(CurrState->Name == StateName)
|
||||
{
|
||||
return CurrState;
|
||||
}
|
||||
}
|
||||
|
||||
UE_LOG(LogTemp, Warning,
|
||||
TEXT("Could not find state in state machine with name %s on %s"), *StateName.ToString(), *Owner->GetName());
|
||||
|
||||
return nullptr;
|
||||
}
|
@ -18,7 +18,7 @@
|
||||
*
|
||||
* This component also calls the appropriate state logic when a state is changed or the component ticks.
|
||||
*/
|
||||
UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
|
||||
UCLASS( ClassGroup=(UnrealFightingFramework), meta=(BlueprintSpawnableComponent) )
|
||||
class UNREALFIGHTINGFRAMEWORK_API UFFStateMachineComponent : public UActorComponent, public IFFSystemInterface
|
||||
{
|
||||
GENERATED_BODY()
|
||||
@ -69,18 +69,30 @@ public:
|
||||
*/
|
||||
void SwitchStates(UFFState* NewState);
|
||||
|
||||
/**
|
||||
* Transitions from CurrentState to the default entry state
|
||||
*/
|
||||
void SwitchToEntryState();
|
||||
|
||||
UFUNCTION(BlueprintPure)
|
||||
FORCEINLINE int64 GetTicksInState() const;
|
||||
|
||||
/**
|
||||
* Returns the name of the current state
|
||||
*/
|
||||
UFUNCTION(BlueprintPure)
|
||||
FName GetCurrentStateName() const;
|
||||
FORCEINLINE FName GetCurrentStateName() const;
|
||||
|
||||
/**
|
||||
UFUNCTION(BlueprintPure)
|
||||
FORCEINLINE FName GetCurrentSubStateLabel() const;
|
||||
|
||||
UFUNCTION(BlueprintCallable)
|
||||
FORCEINLINE void SetSubStateLabel(FName InSubStateLabel);
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
FFFStateContext GetCurrentStateContext() const;
|
||||
|
||||
void SetSubStateLabel(FName InSubStateLabel);
|
||||
FFFStateContext GetCurrentStateContext();
|
||||
|
||||
// IFFSystemInterface interface
|
||||
virtual void FixedTick(float OneFrame) override;
|
||||
@ -91,36 +103,42 @@ protected:
|
||||
* Actor that owns this state machine.
|
||||
* This will typically be a player controller that possesses the avatar.
|
||||
*/
|
||||
UPROPERTY(BlueprintReadOnly)
|
||||
UPROPERTY()
|
||||
AActor* Owner;
|
||||
|
||||
/**
|
||||
* The avatar is an actor that this state machine represents.
|
||||
* This will typically be a pawn or character the state machine is attached to.
|
||||
*/
|
||||
UPROPERTY(BlueprintReadOnly)
|
||||
UPROPERTY()
|
||||
AActor* Avatar;
|
||||
|
||||
/** How many ticks have elapsed since the currently active state was entered */
|
||||
UPROPERTY(BlueprintReadOnly, Category="UFF|State")
|
||||
int64 TicksInState;
|
||||
|
||||
/**
|
||||
* States classes to create and add to this state machine when the game starts
|
||||
* 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 */
|
||||
UPROPERTY(BlueprintReadOnly)
|
||||
UPROPERTY()
|
||||
UFFState* CurrentState;
|
||||
|
||||
/** Current SubState label or NAME_None if there is no SubState label set for the current state*/
|
||||
UPROPERTY(BlueprintReadOnly)
|
||||
FName CurrentSubStateLabel;
|
||||
|
||||
// States that have been added
|
||||
UPROPERTY(BlueprintReadOnly)
|
||||
UPROPERTY()
|
||||
TArray<UFFState*> States;
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user