Start creating custom state machine asset type

This commit is contained in:
Kevin Poretti 2022-03-30 21:49:09 -04:00
parent ec0735ceca
commit 1501e35ad7
81 changed files with 498 additions and 493 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -6,6 +6,7 @@
#include "DrawDebugHelpers.h" #include "DrawDebugHelpers.h"
#include "Camera/CameraComponent.h" #include "Camera/CameraComponent.h"
#include "Components/CapsuleComponent.h" #include "Components/CapsuleComponent.h"
#include "Components/InputComponent.h"
#include "Components/SNGCharacterMovementComponent.h" #include "Components/SNGCharacterMovementComponent.h"
#include "GameFramework/SpringArmComponent.h" #include "GameFramework/SpringArmComponent.h"
#include "Kismet/KismetMathLibrary.h" #include "Kismet/KismetMathLibrary.h"

View File

@ -4,6 +4,7 @@
#include "Characters/SNGProtagonist.h" #include "Characters/SNGProtagonist.h"
#include "DrawDebugHelpers.h" #include "DrawDebugHelpers.h"
#include "Animation/AnimInstance.h"
#include "GameFramework/CharacterMovementComponent.h" #include "GameFramework/CharacterMovementComponent.h"
#include "Kismet/KismetMathLibrary.h" #include "Kismet/KismetMathLibrary.h"
#include "Kismet/KismetSystemLibrary.h" #include "Kismet/KismetSystemLibrary.h"

View File

@ -1,15 +1,15 @@
// Project Sword & Gun Copyright © 2021 Kevin Poretti // Project Sword & Gun Copyright © 2021 Kevin Poretti
#include "States/SNGEnemyBaseState.h" #include "States/OLD/SNGEnemyBaseState.h"
void USNGEnemyBaseState::SetOwner(AActor* StateOwner) void USNGEnemyBaseState::SetOwner(AActor* StateOwner)
{ {
Super::SetOwner(StateOwner); Super::SetOwner(StateOwner);
Enemy = Cast<ASNGEnemyBase>(StateOwner); Enemy = Cast<ASNGEnemyBase>(StateOwner);
if(!Enemy) if(!Enemy)
{ {
UE_LOG(LogTemp, Error, TEXT("SNGEnemyBaseState :: Could not cast state owner to SNGEnemyBase")); UE_LOG(LogTemp, Error, TEXT("SNGEnemyBaseState :: Could not cast state owner to SNGEnemyBase"));
} }
} }

View File

@ -1,15 +1,15 @@
// Project Sword & Gun Copyright © 2021 Kevin Poretti // Project Sword & Gun Copyright © 2021 Kevin Poretti
#include "States/SNGProtagonistState.h" #include "States/OLD/SNGProtagonistState.h"
void USNGProtagonistState::SetOwner(AActor* StateOwner) void USNGProtagonistState::SetOwner(AActor* StateOwner)
{ {
Super::SetOwner(StateOwner); Super::SetOwner(StateOwner);
Protagonist = Cast<ASNGProtagonist>(StateOwner); Protagonist = Cast<ASNGProtagonist>(StateOwner);
if(!Protagonist) if(!Protagonist)
{ {
UE_LOG(LogTemp, Error, TEXT("SNGProtagonistState :: Could not cast state owner to SNGProtagonist")); UE_LOG(LogTemp, Error, TEXT("SNGProtagonistState :: Could not cast state owner to SNGProtagonist"));
} }
} }

View File

@ -1,204 +1,204 @@
// Project Sword & Gun Copyright © 2021 Kevin Poretti // Project Sword & Gun Copyright © 2021 Kevin Poretti
#include "States/SNGState.h" #include "States/OLD/SNGState.h"
USNGState::USNGState() USNGState::USNGState()
{ {
Name = NAME_None; Name = NAME_None;
TimeInState = 0.0f; TimeInState = 0.0f;
bCanTransitionToItself = false; bCanTransitionToItself = false;
DefaultSubStateIndex = 0; DefaultSubStateIndex = 0;
} }
void USNGState::RegisterTransition(FName DestState, FName TransitionRuleFunctionName) void USNGState::RegisterTransition(FName DestState, FName TransitionRuleFunctionName)
{ {
FStateTransitionRule StateTransitionRule; FStateTransitionRule StateTransitionRule;
StateTransitionRule.BindUFunction(this, TransitionRuleFunctionName); StateTransitionRule.BindUFunction(this, TransitionRuleFunctionName);
if(!Transitions.Contains(DestState)) if(!Transitions.Contains(DestState))
{ {
Transitions.Add(DestState, StateTransitionRule); Transitions.Add(DestState, StateTransitionRule);
} }
else else
{ {
UE_LOG(LogTemp, Warning, TEXT("USNGState :: Transition dictionary already contains transition rule for destination state %s"), *DestState.ToString()); UE_LOG(LogTemp, Warning, TEXT("USNGState :: Transition dictionary already contains transition rule for destination state %s"), *DestState.ToString());
} }
} }
void USNGState::RegisterEventHandler(ESNGEventType EventType, FName EventHandlerFunctionName) void USNGState::RegisterEventHandler(ESNGEventType EventType, FName EventHandlerFunctionName)
{ {
FEventHandlerRule EventHandlerRule; FEventHandlerRule EventHandlerRule;
EventHandlerRule.BindUFunction(this, EventHandlerFunctionName); EventHandlerRule.BindUFunction(this, EventHandlerFunctionName);
if(Handlers.Contains(EventType)) if(Handlers.Contains(EventType))
{ {
Handlers[EventType].Add(EventHandlerRule); Handlers[EventType].Add(EventHandlerRule);
} }
else else
{ {
Handlers.Add(EventType, TArray<FEventHandlerRule>()); Handlers.Add(EventType, TArray<FEventHandlerRule>());
Handlers[EventType].Add(EventHandlerRule); Handlers[EventType].Add(EventHandlerRule);
} }
} }
FName USNGState::GetNextStateFromEvent(FSNGEvent& Event) FName USNGState::GetNextStateFromEvent(FSNGEvent& Event)
{ {
FName DestState = NAME_None; FName DestState = NAME_None;
if(Handlers.Contains(Event.EventType)) if(Handlers.Contains(Event.EventType))
{ {
for (auto EventHandler : Handlers[Event.EventType]) for (auto EventHandler : Handlers[Event.EventType])
{ {
// FStateTransitionRule is a delegate that returns true if the transition rules are met // FStateTransitionRule is a delegate that returns true if the transition rules are met
// and false otherwise // and false otherwise
if(!EventHandler.IsBound()) if(!EventHandler.IsBound())
{ {
UE_LOG(LogTemp, Error, TEXT("SNGState :: Tried calling function %s but it is not bound"), *EventHandler.GetFunctionName().ToString()); UE_LOG(LogTemp, Error, TEXT("SNGState :: Tried calling function %s but it is not bound"), *EventHandler.GetFunctionName().ToString());
continue; continue;
} }
DestState = EventHandler.Execute(Event); DestState = EventHandler.Execute(Event);
if(DestState != NAME_None) if(DestState != NAME_None)
{ {
return DestState; return DestState;
} }
} }
} }
if(Parent) if(Parent)
{ {
return Parent->GetNextStateFromEvent(Event); return Parent->GetNextStateFromEvent(Event);
} }
return NAME_None; return NAME_None;
} }
FName USNGState::GetNextState() FName USNGState::GetNextState()
{ {
// NOTE(kevin): Does this actually have to be a map? // NOTE(kevin): Does this actually have to be a map?
for(const TPair<FName, FStateTransitionRule>& pair : Transitions) for(const TPair<FName, FStateTransitionRule>& pair : Transitions)
{ {
// FStateTransitionRule is a delegate that returns true if the transition rules are met // FStateTransitionRule is a delegate that returns true if the transition rules are met
// and false otherwise // and false otherwise
if(!pair.Value.IsBound()) if(!pair.Value.IsBound())
{ {
UE_LOG(LogTemp, Error, TEXT("SNGState :: Tried calling function %s but it is not bound"), *pair.Value.GetFunctionName().ToString()); UE_LOG(LogTemp, Error, TEXT("SNGState :: Tried calling function %s but it is not bound"), *pair.Value.GetFunctionName().ToString());
continue; continue;
} }
if(pair.Value.Execute()) if(pair.Value.Execute())
{ {
return pair.Key; return pair.Key;
} }
} }
if(Parent) if(Parent)
{ {
return Parent->GetNextState(); return Parent->GetNextState();
} }
return NAME_None; return NAME_None;
} }
AActor* USNGState::GetOwner() AActor* USNGState::GetOwner()
{ {
return Owner; return Owner;
} }
void USNGState::SetOwner(AActor* StateOwner) void USNGState::SetOwner(AActor* StateOwner)
{ {
Owner = StateOwner; Owner = StateOwner;
} }
USNGState* USNGState::GetParent() USNGState* USNGState::GetParent()
{ {
return Parent; return Parent;
} }
void USNGState::SetParent(USNGState* ParentState) void USNGState::SetParent(USNGState* ParentState)
{ {
this->Parent = ParentState; this->Parent = ParentState;
} }
uint32 USNGState::GetDepth() uint32 USNGState::GetDepth()
{ {
return Depth; return Depth;
} }
void USNGState::CreateState() void USNGState::CreateState()
{ {
// pre-compute the depth/level of this state during creation // pre-compute the depth/level of this state during creation
// used later for calculating least common ancestor of two states // used later for calculating least common ancestor of two states
uint32 CurrDepth = 0; uint32 CurrDepth = 0;
USNGState* CurrState = this; USNGState* CurrState = this;
while(CurrState->Parent != nullptr) while(CurrState->Parent != nullptr)
{ {
CurrDepth++; CurrDepth++;
CurrState = CurrState->Parent; CurrState = CurrState->Parent;
} }
Depth = CurrDepth; Depth = CurrDepth;
OnCreateState(); OnCreateState();
} }
USNGState* USNGState::EnterState(FSNGEvent& Event) USNGState* USNGState::EnterState(FSNGEvent& Event)
{ {
OnEnterState(Event); OnEnterState(Event);
TimeInState = 0.0f; TimeInState = 0.0f;
if(SubStates.Num() > 0 && if(SubStates.Num() > 0 &&
(DefaultSubStateIndex >= 0 && DefaultSubStateIndex < SubStates.Num())) (DefaultSubStateIndex >= 0 && DefaultSubStateIndex < SubStates.Num()))
{ {
return SubStates[DefaultSubStateIndex]->EnterState(Event); return SubStates[DefaultSubStateIndex]->EnterState(Event);
} }
return this; return this;
} }
void USNGState::ExitState() void USNGState::ExitState()
{ {
OnExitState(); OnExitState();
// to do this correctly i think we need to find the shared parent of the current state and the next state // to do this correctly i think we need to find the shared parent of the current state and the next state
// we only want to exit states until that point // we only want to exit states until that point
if(Parent) if(Parent)
{ {
Parent->ExitState(); Parent->ExitState();
} }
} }
void USNGState::UpdateState(float DeltaTime) void USNGState::UpdateState(float DeltaTime)
{ {
OnUpdateState(DeltaTime); OnUpdateState(DeltaTime);
TimeInState += DeltaTime; TimeInState += DeltaTime;
if(Parent) if(Parent)
{ {
Parent->UpdateState(DeltaTime); Parent->UpdateState(DeltaTime);
} }
} }
FName USNGState::GetName() FName USNGState::GetName()
{ {
return Name; return Name;
} }
float USNGState::GetTimeInState() float USNGState::GetTimeInState()
{ {
return TimeInState; return TimeInState;
} }
bool USNGState::CanTransitionToItself() bool USNGState::CanTransitionToItself()
{ {
return bCanTransitionToItself; return bCanTransitionToItself;
} }
TArray<TSubclassOf<USNGState>> USNGState::GetSubStateClasses() TArray<TSubclassOf<USNGState>> USNGState::GetSubStateClasses()
{ {
return SubStateClasses; return SubStateClasses;
} }
void USNGState::AddSubState(USNGState* SubState) void USNGState::AddSubState(USNGState* SubState)
{ {
SubStates.Add(SubState); SubStates.Add(SubState);
} }

View File

@ -5,6 +5,7 @@
#include "DrawDebugHelpers.h" #include "DrawDebugHelpers.h"
#include "Characters/SNGCharacterBase_DEPRECATED.h" #include "Characters/SNGCharacterBase_DEPRECATED.h"
#include "GameFramework/DamageType.h"
#include "Kismet/GameplayStatics.h" #include "Kismet/GameplayStatics.h"
#include "Particles/ParticleSystemComponent.h" #include "Particles/ParticleSystemComponent.h"
#include "PhysicalMaterials/PhysicalMaterial.h" #include "PhysicalMaterials/PhysicalMaterial.h"

View File

@ -5,6 +5,7 @@
#include "Characters/SNGCharacterBase_DEPRECATED.h" #include "Characters/SNGCharacterBase_DEPRECATED.h"
#include "GameFramework/DamageType.h"
#include "Kismet/KismetSystemLibrary.h" #include "Kismet/KismetSystemLibrary.h"
#include "SwordNGun/SwordNGun.h" #include "SwordNGun/SwordNGun.h"

View File

@ -3,7 +3,7 @@
#pragma once #pragma once
#include "CoreMinimal.h" #include "CoreMinimal.h"
#include "States/SNGState.h" #include "States/OLD/SNGState.h"
#include "Components/ActorComponent.h" #include "Components/ActorComponent.h"
#include "Interfaces/SNGEventProcessorInterface.h" #include "Interfaces/SNGEventProcessorInterface.h"

View File

@ -1,25 +1,25 @@
// Project Sword & Gun Copyright © 2021 Kevin Poretti // Project Sword & Gun Copyright © 2021 Kevin Poretti
#pragma once #pragma once
#include "CoreMinimal.h" #include "CoreMinimal.h"
#include "Characters/SNGEnemyBase.h" #include "Characters/SNGEnemyBase.h"
#include "States/SNGState.h" #include "States/OLD/SNGState.h"
#include "SNGEnemyBaseState.generated.h" #include "SNGEnemyBaseState.generated.h"
/** /**
* *
*/ */
UCLASS() UCLASS()
class SWORDNGUN_API USNGEnemyBaseState : public USNGState class SWORDNGUN_API USNGEnemyBaseState : public USNGState
{ {
GENERATED_BODY() GENERATED_BODY()
public: public:
virtual void SetOwner(AActor* StateOwner) override; virtual void SetOwner(AActor* StateOwner) override;
protected: protected:
UPROPERTY(BlueprintReadOnly) UPROPERTY(BlueprintReadOnly)
ASNGEnemyBase* Enemy; ASNGEnemyBase* Enemy;
}; };

View File

@ -1,25 +1,25 @@
// Project Sword & Gun Copyright © 2021 Kevin Poretti // Project Sword & Gun Copyright © 2021 Kevin Poretti
#pragma once #pragma once
#include "CoreMinimal.h" #include "CoreMinimal.h"
#include "Characters/SNGProtagonist.h" #include "Characters/SNGProtagonist.h"
#include "States/SNGState.h" #include "States/OLD/SNGState.h"
#include "SNGProtagonistState.generated.h" #include "SNGProtagonistState.generated.h"
/** /**
* *
*/ */
UCLASS() UCLASS()
class SWORDNGUN_API USNGProtagonistState : public USNGState class SWORDNGUN_API USNGProtagonistState : public USNGState
{ {
GENERATED_BODY() GENERATED_BODY()
public: public:
virtual void SetOwner(AActor* StateOwner) override; virtual void SetOwner(AActor* StateOwner) override;
protected: protected:
UPROPERTY(BlueprintReadOnly) UPROPERTY(BlueprintReadOnly)
ASNGProtagonist* Protagonist; ASNGProtagonist* Protagonist;
}; };

View File

@ -1,110 +1,110 @@
// Project Sword & Gun Copyright © 2021 Kevin Poretti // Project Sword & Gun Copyright © 2021 Kevin Poretti
#pragma once #pragma once
#include "CoreMinimal.h" #include "CoreMinimal.h"
#include "SwordNGun/SNGTypes.h" #include "SwordNGun/SNGTypes.h"
#include "SNGState.generated.h" #include "SNGState.generated.h"
DECLARE_DYNAMIC_DELEGATE_RetVal(bool, FStateTransitionRule); DECLARE_DYNAMIC_DELEGATE_RetVal(bool, FStateTransitionRule);
DECLARE_DYNAMIC_DELEGATE_RetVal_OneParam(FName, FEventHandlerRule, FSNGEvent&, Event); DECLARE_DYNAMIC_DELEGATE_RetVal_OneParam(FName, FEventHandlerRule, FSNGEvent&, Event);
/** /**
* *
*/ */
UCLASS(Blueprintable) UCLASS(Blueprintable)
class SWORDNGUN_API USNGState : public UObject class SWORDNGUN_API USNGState : public UObject
{ {
GENERATED_BODY() GENERATED_BODY()
public: public:
USNGState(); USNGState();
UFUNCTION(BlueprintCallable) UFUNCTION(BlueprintCallable)
void RegisterTransition(FName DestState, FName TransitionRuleFunctionName); void RegisterTransition(FName DestState, FName TransitionRuleFunctionName);
UFUNCTION(BlueprintCallable) UFUNCTION(BlueprintCallable)
void RegisterEventHandler(ESNGEventType EventType, FName EventHandlerFunctionName); void RegisterEventHandler(ESNGEventType EventType, FName EventHandlerFunctionName);
FName GetName(); FName GetName();
float GetTimeInState(); float GetTimeInState();
bool CanTransitionToItself(); bool CanTransitionToItself();
UFUNCTION(BlueprintCallable) UFUNCTION(BlueprintCallable)
AActor* GetOwner(); AActor* GetOwner();
virtual void SetOwner(AActor* StateOwner); virtual void SetOwner(AActor* StateOwner);
USNGState* GetParent(); USNGState* GetParent();
void SetParent(USNGState* ParentState); void SetParent(USNGState* ParentState);
uint32 GetDepth(); uint32 GetDepth();
TArray<TSubclassOf<USNGState>> GetSubStateClasses(); TArray<TSubclassOf<USNGState>> GetSubStateClasses();
void AddSubState(USNGState* SubState); void AddSubState(USNGState* SubState);
// returns name of the next state if event triggers a state transition // returns name of the next state if event triggers a state transition
FName GetNextStateFromEvent(FSNGEvent& Event); FName GetNextStateFromEvent(FSNGEvent& Event);
// executes transitions rules for this state to determine what substate // executes transitions rules for this state to determine what substate
FName GetNextState(); FName GetNextState();
void CreateState(); void CreateState();
USNGState* EnterState(FSNGEvent& Event); USNGState* EnterState(FSNGEvent& Event);
void ExitState(); void ExitState();
void UpdateState(float DeltaTime); void UpdateState(float DeltaTime);
protected: protected:
UPROPERTY(EditDefaultsOnly) UPROPERTY(EditDefaultsOnly)
FName Name; FName Name;
UPROPERTY(BlueprintReadOnly) UPROPERTY(BlueprintReadOnly)
float TimeInState; float TimeInState;
UPROPERTY(EditDefaultsOnly) UPROPERTY(EditDefaultsOnly)
bool bCanTransitionToItself; bool bCanTransitionToItself;
UPROPERTY(EditDefaultsOnly, Category="Sub states", meta = (ClampMin = -1)) UPROPERTY(EditDefaultsOnly, Category="Sub states", meta = (ClampMin = -1))
int32 DefaultSubStateIndex; int32 DefaultSubStateIndex;
UPROPERTY(EditDefaultsOnly, Category="Sub states") UPROPERTY(EditDefaultsOnly, Category="Sub states")
TArray<TSubclassOf<USNGState>> SubStateClasses; TArray<TSubclassOf<USNGState>> SubStateClasses;
TArray<USNGState*> SubStates; TArray<USNGState*> SubStates;
AActor* Owner; AActor* Owner;
USNGState* Parent; USNGState* Parent;
// distance from root node // distance from root node
uint32 Depth; uint32 Depth;
// NOTE(kevin): I don't think this needs to be a map // NOTE(kevin): I don't think this needs to be a map
TMap<FName, FStateTransitionRule> Transitions; TMap<FName, FStateTransitionRule> Transitions;
TMap<ESNGEventType, TArray<FEventHandlerRule>> Handlers; TMap<ESNGEventType, TArray<FEventHandlerRule>> Handlers;
UFUNCTION(BlueprintImplementableEvent) UFUNCTION(BlueprintImplementableEvent)
void OnCreateState(); void OnCreateState();
UFUNCTION(BlueprintImplementableEvent) UFUNCTION(BlueprintImplementableEvent)
void OnEnterState(FSNGEvent Event); void OnEnterState(FSNGEvent Event);
UFUNCTION(BlueprintImplementableEvent) UFUNCTION(BlueprintImplementableEvent)
void OnExitState(); void OnExitState();
UFUNCTION(BlueprintImplementableEvent) UFUNCTION(BlueprintImplementableEvent)
void OnUpdateState(float DeltaTime); void OnUpdateState(float DeltaTime);
}; };

View File

@ -8,7 +8,7 @@ public class SwordNGun : ModuleRules
{ {
PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs; PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "PhysicsCore" }); PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "PhysicsCore", "UnrealEd", "AssetTools" });
PrivateDependencyModuleNames.AddRange(new string[] { }); PrivateDependencyModuleNames.AddRange(new string[] { });

View File

@ -10,7 +10,8 @@
"LoadingPhase": "Default", "LoadingPhase": "Default",
"AdditionalDependencies": [ "AdditionalDependencies": [
"Engine", "Engine",
"CoreUObject" "CoreUObject",
"UnrealEd"
] ]
} }
], ],