Implement rest of state class and do transition logic in state machine
This commit is contained in:
parent
4cf3834b2d
commit
d7245957df
@ -1,4 +0,0 @@
|
|||||||
// Unreal Fighting Framework by Kevin Poretti
|
|
||||||
|
|
||||||
|
|
||||||
#include "IFFSystemInterface.h"
|
|
@ -33,6 +33,19 @@ void AFFPlayerController::FixedTick(float OneFrame)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool AFFPlayerController::CheckInputSequences(const TArray<FFFInputSequence>& InputSequences)
|
||||||
|
{
|
||||||
|
for(const FFFInputSequence& ThisInputSequence : InputSequences)
|
||||||
|
{
|
||||||
|
if(InputBuffer->CheckInputSequence(ThisInputSequence))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void AFFPlayerController::SetupInputComponent()
|
void AFFPlayerController::SetupInputComponent()
|
||||||
{
|
{
|
||||||
Super::SetupInputComponent();
|
Super::SetupInputComponent();
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
#include "FFInputBufferComponent.h"
|
#include "FFInputBufferComponent.h"
|
||||||
#include "IFFSystemInterface.h"
|
#include "IFFSystemInterface.h"
|
||||||
#include "Utils/TCircleBuffer.h"
|
#include "Utils/TCircleBuffer.h"
|
||||||
|
#include "State/IFFStateOwnerInterface.h"
|
||||||
|
|
||||||
// UE includes
|
// UE includes
|
||||||
#include "CoreMinimal.h"
|
#include "CoreMinimal.h"
|
||||||
@ -19,7 +20,7 @@
|
|||||||
* unacknowledged inputs to a remote client or server for processing.
|
* unacknowledged inputs to a remote client or server for processing.
|
||||||
*/
|
*/
|
||||||
UCLASS()
|
UCLASS()
|
||||||
class UNREALFIGHTINGFRAMEWORK_API AFFPlayerController : public APlayerController, public IFFSystemInterface
|
class UNREALFIGHTINGFRAMEWORK_API AFFPlayerController : public APlayerController, public IFFSystemInterface, public IFFStateOwnerInterface
|
||||||
{
|
{
|
||||||
GENERATED_BODY()
|
GENERATED_BODY()
|
||||||
|
|
||||||
@ -50,6 +51,10 @@ public:
|
|||||||
virtual void FixedTick(float OneFrame) override;
|
virtual void FixedTick(float OneFrame) override;
|
||||||
// End of IFFSystemInterface
|
// End of IFFSystemInterface
|
||||||
|
|
||||||
|
// IFFStateOwnerInterface
|
||||||
|
virtual bool CheckInputSequences(const TArray<FFFInputSequence>& InputSequences) override;
|
||||||
|
// End of IFFStateOwnerInterface
|
||||||
|
|
||||||
// APlayerController interface
|
// APlayerController interface
|
||||||
virtual void SetupInputComponent() override;
|
virtual void SetupInputComponent() override;
|
||||||
// End of APlayerController interface
|
// End of APlayerController interface
|
||||||
|
@ -4,61 +4,97 @@
|
|||||||
|
|
||||||
// FF includes
|
// FF includes
|
||||||
#include "FFStateMachineComponent.h"
|
#include "FFStateMachineComponent.h"
|
||||||
|
#include "IFFStateAvatarInterface.h"
|
||||||
|
#include "IFFStateOwnerInterface.h"
|
||||||
|
|
||||||
|
// UE includes
|
||||||
|
#include "Components/SkeletalMeshComponent.h"
|
||||||
|
|
||||||
void UFFStateBehavior::Enter(const FFFStateContext& InStateContext)
|
void UFFState::Enter(const FFFStateContext& InStateContext)
|
||||||
{
|
{
|
||||||
|
if(InStateContext.Avatar)
|
||||||
|
{
|
||||||
|
USkeletalMeshComponent* SMC = InStateContext.Avatar->GetComponentByClass<USkeletalMeshComponent>();
|
||||||
|
if(SMC && MontageToPlay)
|
||||||
|
{
|
||||||
|
SMC->GetAnimInstance()->Montage_Play(MontageToPlay);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
OnEnter(InStateContext);
|
OnEnter(InStateContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void UFFStateBehavior::Exit(const FFFStateContext& InStateContext)
|
void UFFState::Exit(const FFFStateContext& InStateContext)
|
||||||
{
|
{
|
||||||
|
if(InStateContext.Avatar)
|
||||||
|
{
|
||||||
|
USkeletalMeshComponent* SMC = InStateContext.Avatar->GetComponentByClass<USkeletalMeshComponent>();
|
||||||
|
if(SMC && MontageToPlay)
|
||||||
|
{
|
||||||
|
FAlphaBlendArgs BlendOutArgs = MontageToPlay->GetBlendOutArgs();
|
||||||
|
SMC->GetAnimInstance()->Montage_Stop(BlendOutArgs.BlendTime, MontageToPlay);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
OnExit(InStateContext);
|
OnExit(InStateContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void UFFStateBehavior::Update(float OneFrame, const FFFStateContext& InStateContext)
|
void UFFState::Update(float OneFrame, const FFFStateContext& InStateContext)
|
||||||
{
|
{
|
||||||
OnUpdate(OneFrame, InStateContext);
|
OnUpdate(OneFrame, InStateContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
void UFFStateBehavior::OnLanded_Implementation(const FFFStateContext& InStateContext)
|
|
||||||
|
bool UFFState::CanTransition_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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void UFFStateBehavior::OnEnter_Implementation(const FFFStateContext& InStateContext)
|
void UFFState::GotoSubState(FName InSubStateLabel)
|
||||||
{
|
{
|
||||||
|
UFFStateMachineComponent* SMC = Cast<UFFStateMachineComponent>(GetOuter());
|
||||||
|
if(SMC)
|
||||||
|
{
|
||||||
|
SMC->SetSubStateLabel(InSubStateLabel);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void UFFStateBehavior::OnExit_Implementation(const FFFStateContext& InStateContext)
|
UWorld* UFFState::GetWorld() const
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void UFFStateBehavior::OnUpdate_Implementation(float OneFrame, const FFFStateContext& InStateContext)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void UFFStateBehavior::OnHit_Implementation(const FFFStateContext& InStateContext)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void UFFStateBehavior::OnBlock_Implementation(const FFFStateContext& InStateContext)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void UFFStateBehavior::OnInputEvent_Implementation(const FFFStateContext& InStateContext)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
UWorld* UFFStateBehavior::GetWorld() const
|
|
||||||
{
|
{
|
||||||
UFFStateMachineComponent* SMC = Cast<UFFStateMachineComponent>(GetOuter());
|
UFFStateMachineComponent* SMC = Cast<UFFStateMachineComponent>(GetOuter());
|
||||||
if(SMC)
|
if(SMC)
|
||||||
|
@ -2,29 +2,14 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
// FF includes
|
||||||
|
#include "Input/FFInputBufferComponent.h"
|
||||||
|
|
||||||
// UE includes
|
// UE includes
|
||||||
#include "CoreMinimal.h"
|
#include "CoreMinimal.h"
|
||||||
|
|
||||||
#include "FFState.generated.h"
|
#include "FFState.generated.h"
|
||||||
|
|
||||||
USTRUCT(BlueprintType)
|
|
||||||
struct FFFStateData
|
|
||||||
{
|
|
||||||
GENERATED_BODY()
|
|
||||||
|
|
||||||
/** Name of this state */
|
|
||||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category="UFF|State")
|
|
||||||
FName Name;
|
|
||||||
|
|
||||||
/** Conditions that need to be met in order for this state to be transitioned into */
|
|
||||||
UPROPERTY(EditAnywhere)
|
|
||||||
TArray<uint8> EntryConditions;
|
|
||||||
|
|
||||||
/** What is this state's category. Used for determining what types of state can prematurely cancel this one. */
|
|
||||||
UPROPERTY(EditAnywhere)
|
|
||||||
uint8 StateType;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
USTRUCT(BlueprintType)
|
USTRUCT(BlueprintType)
|
||||||
struct FFFStateContext
|
struct FFFStateContext
|
||||||
@ -40,11 +25,13 @@ struct FFFStateContext
|
|||||||
*/
|
*/
|
||||||
AActor* Avatar;
|
AActor* Avatar;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Data associated with this state.
|
* Parent state machine that controls this state
|
||||||
* For example this can be new movement values or data about the hitboxes if this state represents an attack.
|
*/
|
||||||
*/
|
const class UFFStateMachineComponent* Parent;
|
||||||
FFFStateData StateData;
|
|
||||||
|
/** The number of ticks that have elapsed since this state was entered into */
|
||||||
|
int64 TicksInState;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -52,68 +39,132 @@ struct FFFStateContext
|
|||||||
* and logic to run when the state is entered, exited, and active.
|
* and logic to run when the state is entered, exited, and active.
|
||||||
*/
|
*/
|
||||||
UCLASS()
|
UCLASS()
|
||||||
class UNREALFIGHTINGFRAMEWORK_API UFFStateBehavior : public UObject
|
class UNREALFIGHTINGFRAMEWORK_API UFFState : public UObject
|
||||||
{
|
{
|
||||||
GENERATED_BODY()
|
GENERATED_BODY()
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
// State parameters (should be read-only)
|
||||||
/** Name of this state behavior */
|
/** Name of this state behavior */
|
||||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category="UFF|State")
|
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="UFF State Properties")
|
||||||
FName Name;
|
FName Name;
|
||||||
|
|
||||||
// TODO: since state's are now purely behavioral can we remove these function calls?
|
|
||||||
// They are basically redundant with OnEnter, OnUpdate, OnExit, etc.
|
|
||||||
/**
|
/**
|
||||||
|
* How long this state will be active before finishing if this state is not cancelled out of
|
||||||
|
* by other means.
|
||||||
|
*/
|
||||||
|
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="UFF State Properties")
|
||||||
|
int64 StateDuration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* What stance the object this state represents must be in.
|
||||||
|
* For example this is usually an enumerated value that signifies if a character needs to be
|
||||||
|
* crouching, standing, or airborne for this state to be eligible for transitioning.
|
||||||
|
*/
|
||||||
|
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="UFF State Properties")
|
||||||
|
uint8 StanceRequired;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* What is this state's category.
|
||||||
|
* Used for determining what types of state can prematurely cancel this one.
|
||||||
|
*/
|
||||||
|
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="UFF State Properties")
|
||||||
|
uint8 StateType;
|
||||||
|
|
||||||
|
/** Conditions that need to be met in order for this state to be transitioned into */
|
||||||
|
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="UFF State Properties")
|
||||||
|
TArray<uint8> EntryConditions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Input sequences that needs to be present in the controlling player's input buffer for this
|
||||||
|
* state to be eligible for transitioning.
|
||||||
|
*/
|
||||||
|
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="UFF State Properties")
|
||||||
|
TArray<FFFInputSequence> InputSequences;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If true the state can transition from itself into itself without having to go through
|
||||||
|
* another state like Idle
|
||||||
|
*/
|
||||||
|
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="UFF State Properties")
|
||||||
|
bool bCanTransitionToSelf = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Animation to begin playing when this state is entered
|
||||||
|
*/
|
||||||
|
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
|
||||||
|
* 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);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
* Called whenever this state is transitioned into.
|
||||||
*
|
*
|
||||||
* Resets TicksInState and calls appropriate Blueprint hooks
|
* Calls appropriate Blueprint hooks.
|
||||||
*/
|
*/
|
||||||
void Enter(const FFFStateContext& InStateContext);
|
virtual void Enter(const FFFStateContext& InStateContext);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called whenever this state is transitioned out of into a new state.
|
* Called whenever this state is transitioned out of into a new state.
|
||||||
|
*
|
||||||
|
* Calls appropriate Blueprint hooks.
|
||||||
*/
|
*/
|
||||||
void Exit(const FFFStateContext& InStateContext);
|
virtual void Exit(const FFFStateContext& InStateContext);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called whenever this state is active and the game logic ticks.
|
* Called whenever this state is active and the game logic ticks.
|
||||||
*
|
*
|
||||||
* Increments TicksInState and calls appropriate Blueprint hooks.
|
* Calls appropriate Blueprint hooks.
|
||||||
*
|
*
|
||||||
* @param OneFrame the time that elapses during one fixed tick
|
* @param OneFrame the time that elapses during one fixed tick
|
||||||
*/
|
*/
|
||||||
void Update(float OneFrame, const FFFStateContext& InStateContext);
|
virtual void Update(float OneFrame, const FFFStateContext& InStateContext);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Blueprint hook that is called whenever this state is transitioned into
|
* Blueprint hook for whenever this state is transitioned into
|
||||||
*/
|
*/
|
||||||
UFUNCTION(BlueprintNativeEvent, Category="UFF|State|Events")
|
UFUNCTION(BlueprintImplementableEvent, Category="UFF|State|Events")
|
||||||
void OnEnter(const FFFStateContext& InStateContext);
|
void OnEnter(const FFFStateContext& InStateContext);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Blueprint hook that is called whenever this state is transitioned out of into a new state
|
* Blueprint hook for whenever this state is transitioned out of into a new state
|
||||||
*/
|
*/
|
||||||
UFUNCTION(BlueprintNativeEvent, Category="UFF|State|Events")
|
UFUNCTION(BlueprintImplementableEvent, Category="UFF|State|Events")
|
||||||
void OnExit(const FFFStateContext& InStateContext);
|
void OnExit(const FFFStateContext& InStateContext);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Blueprint hook that is called whenever this state is active and the game logic ticks
|
* Blueprint hook for whenever this state is active and the game logic ticks.
|
||||||
*
|
*
|
||||||
* @param OneFrame the time that elapses during one fixed tick
|
* @param OneFrame the time that elapses during one fixed tick
|
||||||
*/
|
*/
|
||||||
UFUNCTION(BlueprintNativeEvent, Category="UFF|State|Events")
|
UFUNCTION(BlueprintImplementableEvent, Category="UFF|State|Events")
|
||||||
void OnUpdate(float OneFrame, const FFFStateContext& InStateContext);
|
void OnUpdate(float OneFrame, const FFFStateContext& InStateContext);
|
||||||
|
|
||||||
UFUNCTION(BlueprintNativeEvent, Category="UFF|State|Events")
|
UFUNCTION(BlueprintImplementableEvent, Category="UFF|State|Events")
|
||||||
void OnLanded(const FFFStateContext& InStateContext);
|
void OnLanded(const FFFStateContext& InStateContext);
|
||||||
|
|
||||||
UFUNCTION(BlueprintNativeEvent, Category="UFF|State|Events")
|
UFUNCTION(BlueprintImplementableEvent, Category="UFF|State|Events")
|
||||||
void OnHit(const FFFStateContext& InStateContext);
|
void OnHit(const FFFStateContext& InStateContext);
|
||||||
|
|
||||||
UFUNCTION(BlueprintNativeEvent, Category="UFF|State|Events")
|
UFUNCTION(BlueprintImplementableEvent, Category="UFF|State|Events")
|
||||||
void OnBlock(const FFFStateContext& InStateContext);
|
void OnBlock(const FFFStateContext& InStateContext);
|
||||||
|
|
||||||
UFUNCTION(BlueprintNativeEvent, Category="UFF|State|Events")
|
UFUNCTION(BlueprintImplementableEvent, Category="UFF|State|Events")
|
||||||
void OnInputEvent(const FFFStateContext& InStateContext);
|
void OnInputEvent(const FFFStateContext& InStateContext);
|
||||||
|
|
||||||
// UObject interface
|
// UObject interface
|
||||||
|
@ -1,6 +0,0 @@
|
|||||||
// Unreal Fighting Framework by Kevin Poretti
|
|
||||||
|
|
||||||
|
|
||||||
#include "State/FFStateContextInterface.h"
|
|
||||||
|
|
||||||
// Add default functionality here for any IFFStateContextInterface functions that are not pure virtual.
|
|
25
Source/UnrealFightingFramework/State/FFStateData.h
Normal file
25
Source/UnrealFightingFramework/State/FFStateData.h
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
// Unreal Fighting Framework by Kevin Poretti
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
// FF includes
|
||||||
|
#include "State/FFState.h"
|
||||||
|
|
||||||
|
// UE includes
|
||||||
|
#include "CoreMinimal.h"
|
||||||
|
#include "Engine/DataAsset.h"
|
||||||
|
|
||||||
|
#include "FFStateData.generated.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
UCLASS()
|
||||||
|
class UNREALFIGHTINGFRAMEWORK_API UFFStateData : public UDataAsset
|
||||||
|
{
|
||||||
|
GENERATED_BODY()
|
||||||
|
|
||||||
|
public:
|
||||||
|
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
|
||||||
|
TArray<TSubclassOf<UFFState>> States;
|
||||||
|
};
|
@ -14,9 +14,9 @@ UFFStateMachineComponent::UFFStateMachineComponent()
|
|||||||
|
|
||||||
void UFFStateMachineComponent::Initialize()
|
void UFFStateMachineComponent::Initialize()
|
||||||
{
|
{
|
||||||
for(const TSubclassOf<UFFStateBehavior>& CurrState : DefaultStates)
|
for(const TSubclassOf<UFFState>& CurrState : DefaultStates)
|
||||||
{
|
{
|
||||||
UFFStateBehavior* TempState = AddState(CurrState);
|
UFFState* TempState = AddState(CurrState);
|
||||||
if(!CurrentState) // first state to be created is the entry into this state machine
|
if(!CurrentState) // first state to be created is the entry into this state machine
|
||||||
{
|
{
|
||||||
CurrentState = TempState;
|
CurrentState = TempState;
|
||||||
@ -33,9 +33,9 @@ void UFFStateMachineComponent::InitActorInfo(AActor* InOwner, AActor* InAvatar)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
UFFStateBehavior* UFFStateMachineComponent::AddState(TSubclassOf<UFFStateBehavior> StateClassToAdd)
|
UFFState* UFFStateMachineComponent::AddState(TSubclassOf<UFFState> StateClassToAdd)
|
||||||
{
|
{
|
||||||
UFFStateBehavior* TempState = NewObject<UFFStateBehavior>(this, StateClassToAdd);
|
UFFState* TempState = NewObject<UFFState>(this, StateClassToAdd);
|
||||||
if(TempState)
|
if(TempState)
|
||||||
{
|
{
|
||||||
States.Add(TempState);
|
States.Add(TempState);
|
||||||
@ -46,9 +46,9 @@ UFFStateBehavior* UFFStateMachineComponent::AddState(TSubclassOf<UFFStateBehavio
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void UFFStateMachineComponent::AddStates(const TArray<TSubclassOf<UFFStateBehavior>>& StateClassesToAdd)
|
void UFFStateMachineComponent::AddStates(const TArray<TSubclassOf<UFFState>>& StateClassesToAdd)
|
||||||
{
|
{
|
||||||
for(const TSubclassOf<UFFStateBehavior>& CurrState : StateClassesToAdd)
|
for(const TSubclassOf<UFFState>& CurrState : StateClassesToAdd)
|
||||||
{
|
{
|
||||||
AddState(CurrState);
|
AddState(CurrState);
|
||||||
}
|
}
|
||||||
@ -60,21 +60,24 @@ 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(UFFStateBehavior* NewState)
|
void UFFStateMachineComponent::SwitchStates(UFFState* NewState)
|
||||||
{
|
{
|
||||||
|
check(CurrentState);
|
||||||
check(NewState);
|
check(NewState);
|
||||||
|
|
||||||
|
|
||||||
CurrentState->Exit(GetCurrentStateContext());
|
CurrentState->Exit(GetCurrentStateContext());
|
||||||
CurrentState = NewState;
|
CurrentState = NewState;
|
||||||
CurrentState->Enter(GetCurrentStateContext());
|
CurrentState->Enter(GetCurrentStateContext());
|
||||||
TicksInState = 0;
|
TicksInState = 0;
|
||||||
|
CurrentSubStateLabel = NAME_None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
FName UFFStateMachineComponent::GetCurrentStateName() const
|
FName UFFStateMachineComponent::GetCurrentStateName() const
|
||||||
{
|
{
|
||||||
return CurrentState ? CurrentState->Name : NAME_None;
|
check(CurrentState)
|
||||||
|
|
||||||
|
return CurrentState->Name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -83,13 +86,21 @@ FFFStateContext UFFStateMachineComponent::GetCurrentStateContext() const
|
|||||||
FFFStateContext CurrStateContext;
|
FFFStateContext CurrStateContext;
|
||||||
CurrStateContext.Owner = Owner;
|
CurrStateContext.Owner = Owner;
|
||||||
CurrStateContext.Avatar = Avatar;
|
CurrStateContext.Avatar = Avatar;
|
||||||
|
CurrStateContext.Parent = this;
|
||||||
|
CurrStateContext.TicksInState = TicksInState;
|
||||||
return CurrStateContext;
|
return CurrStateContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
UFFStateBehavior* UFFStateMachineComponent::FindStateWithName(FName StateName)
|
void UFFStateMachineComponent::SetSubStateLabel(FName InSubStateLabel)
|
||||||
{
|
{
|
||||||
for (UFFStateBehavior* CurrState : States)
|
CurrentSubStateLabel = InSubStateLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
UFFState* UFFStateMachineComponent::FindStateWithName(FName StateName)
|
||||||
|
{
|
||||||
|
for (UFFState* CurrState : States)
|
||||||
{
|
{
|
||||||
if(CurrState->Name == StateName)
|
if(CurrState->Name == StateName)
|
||||||
{
|
{
|
||||||
@ -114,32 +125,35 @@ void UFFStateMachineComponent::BeginPlay()
|
|||||||
|
|
||||||
void UFFStateMachineComponent::FixedTick(float OneFrame)
|
void UFFStateMachineComponent::FixedTick(float OneFrame)
|
||||||
{
|
{
|
||||||
// Should we switch states?
|
|
||||||
|
|
||||||
for(UFFStateBehavior* CurrState : States)
|
|
||||||
{
|
|
||||||
// Check if the state is enabled
|
|
||||||
|
|
||||||
// Check state entry conditions if there are any
|
|
||||||
|
|
||||||
// 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
|
|
||||||
|
|
||||||
// Lastly just check if the state we're about to transition into isn't the current state.
|
|
||||||
// It is OK to transition if state's "CanTransitionToSelf" is true
|
|
||||||
|
|
||||||
// SwitchStates(NewState);
|
|
||||||
// return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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);
|
||||||
|
|
||||||
// Tick current state
|
// Should we switch states?
|
||||||
TicksInState++;
|
UFFState* StateToTransitionTo = nullptr;
|
||||||
CurrentState->Update(OneFrame, GetCurrentStateContext());
|
for(UFFState* ThisState : States)
|
||||||
|
{
|
||||||
|
// found a state
|
||||||
|
if(ThisState->CanTransition(GetCurrentStateContext()))
|
||||||
|
{
|
||||||
|
StateToTransitionTo = ThisState;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lastly just check if the state we're about to transition into isn't the current state.
|
||||||
|
// It is OK to transition if state's "CanTransitionToSelf" is true
|
||||||
|
if(StateToTransitionTo &&
|
||||||
|
(CurrentState->Name != StateToTransitionTo->Name || StateToTransitionTo->bCanTransitionToSelf))
|
||||||
|
{
|
||||||
|
SwitchStates(StateToTransitionTo);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Tick current state
|
||||||
|
TicksInState++;
|
||||||
|
CurrentState->Update(OneFrame, GetCurrentStateContext());
|
||||||
|
}
|
||||||
|
|
||||||
// Debug
|
// Debug
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
// FF includes
|
// FF includes
|
||||||
#include "UnrealFightingFramework/IFFSystemInterface.h"
|
#include "IFFSystemInterface.h"
|
||||||
|
#include "FFState.h"
|
||||||
|
|
||||||
// UE includes
|
// UE includes
|
||||||
#include "CoreMinimal.h"
|
#include "CoreMinimal.h"
|
||||||
@ -47,14 +48,14 @@ public:
|
|||||||
*
|
*
|
||||||
* @return A pointer to the state that was added or nullptr if there was an issue adding or creating the state
|
* @return A pointer to the state that was added or nullptr if there was an issue adding or creating the state
|
||||||
*/
|
*/
|
||||||
UFFStateBehavior* AddState(TSubclassOf<UFFStateBehavior> StateClassToAdd);
|
UFFState* AddState(TSubclassOf<UFFState> StateClassToAdd);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an instance of the state classes and adds newly created states to this state machine.
|
* Creates an instance of the state classes and adds newly created states to this state machine.
|
||||||
*
|
*
|
||||||
* @param StateClassesToAdd Array of state class types to be added to this state machine
|
* @param StateClassesToAdd Array of state class types to be added to this state machine
|
||||||
*/
|
*/
|
||||||
void AddStates(const TArray<TSubclassOf<UFFStateBehavior>>& StateClassesToAdd);
|
void AddStates(const TArray<TSubclassOf<UFFState>>& StateClassesToAdd);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Destroys the state with corresponding name and removes it from this state machine.
|
* Destroys the state with corresponding name and removes it from this state machine.
|
||||||
@ -66,7 +67,7 @@ public:
|
|||||||
*
|
*
|
||||||
* 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(UFFStateBehavior* NewState);
|
void SwitchStates(UFFState* NewState);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the name of the current state
|
* Returns the name of the current state
|
||||||
@ -79,6 +80,8 @@ public:
|
|||||||
*/
|
*/
|
||||||
FFFStateContext GetCurrentStateContext() const;
|
FFFStateContext GetCurrentStateContext() const;
|
||||||
|
|
||||||
|
void SetSubStateLabel(FName InSubStateLabel);
|
||||||
|
|
||||||
// IFFSystemInterface interface
|
// IFFSystemInterface interface
|
||||||
virtual void FixedTick(float OneFrame) override;
|
virtual void FixedTick(float OneFrame) override;
|
||||||
// End of IFFSystemInterface interface
|
// End of IFFSystemInterface interface
|
||||||
@ -100,26 +103,30 @@ 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 */
|
||||||
UPROPERTY(BlueprintReadOnly, Category="UFF|State")
|
UPROPERTY(BlueprintReadOnly, Category="UFF|State")
|
||||||
int32 TicksInState;
|
int64 TicksInState;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* States classes to create and add to this state machine when the game starts
|
* States classes to create and add to this state machine when the game starts
|
||||||
*/
|
*/
|
||||||
UPROPERTY(EditDefaultsOnly, Category="UFF|State Machine")
|
UPROPERTY(EditDefaultsOnly, Category="UFF|State Machine")
|
||||||
TArray<TSubclassOf<UFFStateBehavior>> DefaultStates;
|
TArray<TSubclassOf<UFFState>> DefaultStates;
|
||||||
|
|
||||||
/** Current active state for this state machine */
|
/** Current active state for this state machine */
|
||||||
UPROPERTY(BlueprintReadOnly)
|
UPROPERTY(BlueprintReadOnly)
|
||||||
UFFStateBehavior* CurrentState;
|
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
|
// States that have been added
|
||||||
UPROPERTY(BlueprintReadOnly)
|
UPROPERTY(BlueprintReadOnly)
|
||||||
TArray<UFFStateBehavior*> States;
|
TArray<UFFState*> States;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the state with corresponding name
|
* Returns the state with corresponding name
|
||||||
*/
|
*/
|
||||||
UFFStateBehavior* FindStateWithName(FName StateName);
|
UFFState* FindStateWithName(FName StateName);
|
||||||
|
|
||||||
// UActorComponent interface
|
// UActorComponent interface
|
||||||
virtual void BeginPlay() override;
|
virtual void BeginPlay() override;
|
||||||
|
@ -5,10 +5,10 @@
|
|||||||
#include "CoreMinimal.h"
|
#include "CoreMinimal.h"
|
||||||
#include "UObject/Interface.h"
|
#include "UObject/Interface.h"
|
||||||
|
|
||||||
#include "FFStateContextInterface.generated.h"
|
#include "IFFStateAvatarInterface.generated.h"
|
||||||
|
|
||||||
UINTERFACE(MinimalAPI)
|
UINTERFACE(MinimalAPI)
|
||||||
class UFFStateContextInterface : public UInterface
|
class UFFStateAvatarInterface : public UInterface
|
||||||
{
|
{
|
||||||
GENERATED_BODY()
|
GENERATED_BODY()
|
||||||
};
|
};
|
||||||
@ -16,16 +16,14 @@ class UFFStateContextInterface : public UInterface
|
|||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
class UNREALFIGHTINGFRAMEWORK_API IFFStateContextInterface
|
class UNREALFIGHTINGFRAMEWORK_API IFFStateAvatarInterface
|
||||||
{
|
{
|
||||||
GENERATED_BODY()
|
GENERATED_BODY()
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual bool CheckStateEnabled(uint8 StateType) = 0;
|
|
||||||
|
|
||||||
virtual bool CheckStance(uint8 Stance) = 0;
|
virtual bool CheckStance(uint8 Stance) = 0;
|
||||||
|
|
||||||
virtual bool CheckStateEntryConditions(const TArray<uint8>& EntryConditions) = 0;
|
virtual bool CheckStateEnabled(uint8 StateType) = 0;
|
||||||
|
|
||||||
virtual bool CheckInputSequences(const TArray<FFFInputSequence>& InputSequences) = 0;
|
virtual bool CheckStateEntryConditions(const TArray<uint8>& EntryConditions) = 0;
|
||||||
};
|
};
|
@ -0,0 +1,25 @@
|
|||||||
|
// Unreal Fighting Framework by Kevin Poretti
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "CoreMinimal.h"
|
||||||
|
#include "UObject/Interface.h"
|
||||||
|
|
||||||
|
#include "IFFStateOwnerInterface.generated.h"
|
||||||
|
|
||||||
|
UINTERFACE(MinimalAPI)
|
||||||
|
class UFFStateOwnerInterface : public UInterface
|
||||||
|
{
|
||||||
|
GENERATED_BODY()
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class UNREALFIGHTINGFRAMEWORK_API IFFStateOwnerInterface
|
||||||
|
{
|
||||||
|
GENERATED_BODY()
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual bool CheckInputSequences(const TArray<FFFInputSequence>& InputSequences) = 0;
|
||||||
|
};
|
Loading…
Reference in New Issue
Block a user