Optimised GOAP Search
via Cancelling Previous States & Optimising Action Order
This commit is contained in:
parent
08fbc2180d
commit
3121176310
BIN
COMP250_1_2101327_AI/Content/Main.umap
(Stored with Git LFS)
BIN
COMP250_1_2101327_AI/Content/Main.umap
(Stored with Git LFS)
Binary file not shown.
BIN
COMP250_1_2101327_AI/Content/StarterContent/Audio/Collapse01.uasset
(Stored with Git LFS)
BIN
COMP250_1_2101327_AI/Content/StarterContent/Audio/Collapse01.uasset
(Stored with Git LFS)
Binary file not shown.
@ -4,7 +4,6 @@
|
|||||||
#include "GOAPAgent.h"
|
#include "GOAPAgent.h"
|
||||||
|
|
||||||
#include "Actions/Combo_P.h"
|
#include "Actions/Combo_P.h"
|
||||||
#include "Actions/DefaultAttack.h"
|
|
||||||
|
|
||||||
|
|
||||||
// Sets default values for this component's properties
|
// Sets default values for this component's properties
|
||||||
@ -23,30 +22,21 @@ void UGOAPAgent::BeginPlay()
|
|||||||
{
|
{
|
||||||
Super::BeginPlay();
|
Super::BeginPlay();
|
||||||
|
|
||||||
CombatSystem = Cast<ATurnBaseCombatV2>(GetWorld()->GetGameState());
|
//Gets all classes that inherit from UGOAPAction and adds them to the AvailableActions array
|
||||||
|
TArray<UClass*> ActionClasses;
|
||||||
|
GetDerivedClasses(UGOAPAction::StaticClass(), ActionClasses, false);
|
||||||
|
for (UClass* ActionClass : ActionClasses)
|
||||||
|
{
|
||||||
|
UGOAPAction* Action = NewObject<UGOAPAction>(GetWorld(), ActionClass);
|
||||||
|
Action->Init();
|
||||||
|
AvailableActions.Add(Action);
|
||||||
|
}
|
||||||
|
|
||||||
UGOAPAction* DefaultAttack = NewObject<UGOAPAction>(GetWorld(), UDefaultAttack::StaticClass());
|
//Sort AvailableActions by cost
|
||||||
DefaultAttack->Init();
|
AvailableActions.Sort([](const UGOAPAction& A, const UGOAPAction& B) { return A.ActionCost < B.ActionCost; });
|
||||||
AvailableActions.Add(DefaultAttack);
|
|
||||||
UGOAPAction* Combo_P = NewObject<UGOAPAction>(GetWorld(), UCombo_P::StaticClass());
|
|
||||||
Combo_P->Init();
|
|
||||||
AvailableActions.Add(Combo_P);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool UGOAPAgent::BuildActionGraph(UActionNode* Parent, TArray<UActionNode*>& SuccessfulLeaves, UWorldState* WorldState, TMap<FString, int> AgentGoals)
|
||||||
TMap<FString, int> UGOAPAgent::GetWorldState()
|
|
||||||
{
|
|
||||||
TMap<FString, int> WorldState;
|
|
||||||
WorldState.Add("PlayerHealth", *CombatSystem->PlayerHealth);
|
|
||||||
WorldState.Add("EnemyHealth", *CombatSystem->EnemyHealth);
|
|
||||||
WorldState.Add("ProbertiumResource", CombatSystem->EnemyProbertiumResource);
|
|
||||||
WorldState.Add("EisResource", CombatSystem->EnemyEisResource);
|
|
||||||
WorldState.Add("AzosResource", CombatSystem->EnemyAzosResource);
|
|
||||||
WorldState.Add("IroquoidResource", CombatSystem->EnemyIroquoidResource);
|
|
||||||
return WorldState;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool UGOAPAgent::BuildActionGraph(UActionNode* Parent, TArray<UActionNode*>& SuccessfulLeaves, TMap<FString, int> WorldState, TMap<FString, int> AgentGoals)
|
|
||||||
{
|
{
|
||||||
bool bFoundAPlan = false;
|
bool bFoundAPlan = false;
|
||||||
|
|
||||||
@ -54,17 +44,18 @@ bool UGOAPAgent::BuildActionGraph(UActionNode* Parent, TArray<UActionNode*>& Suc
|
|||||||
{
|
{
|
||||||
if (Action->CheckPreConditions(WorldState))
|
if (Action->CheckPreConditions(WorldState))
|
||||||
{
|
{
|
||||||
TMap<FString, int> NewWorldState = Action->ApplyEffects(WorldState);
|
UWorldState* NewWorldState = Action->ApplyEffects(WorldState);
|
||||||
UActionNode* NewNode = NewObject<UActionNode>();
|
UActionNode* NewNode = NewObject<UActionNode>();
|
||||||
NewNode->Init(Parent, Action, NewWorldState, Parent->Cost + Action->ActionCost);
|
NewNode->Init(Parent, Action, NewWorldState, Parent->Cost + Action->ActionCost);
|
||||||
|
|
||||||
if (NewWorldState["PlayerHealth"] <= 0)
|
if (NewWorldState->State["PlayerHealth"] <= 0)
|
||||||
{
|
{
|
||||||
SuccessfulLeaves.Add(NewNode);
|
SuccessfulLeaves.Add(NewNode);
|
||||||
bFoundAPlan = true;
|
bFoundAPlan = true;
|
||||||
}
|
}
|
||||||
else
|
else if (!SeenStates.Contains(NewWorldState) && !bFoundAPlan)
|
||||||
{
|
{
|
||||||
|
SeenStates.Add(NewWorldState);
|
||||||
TArray<UActionNode*> NewLeaves;
|
TArray<UActionNode*> NewLeaves;
|
||||||
if (BuildActionGraph(NewNode, NewLeaves, NewWorldState, AgentGoals))
|
if (BuildActionGraph(NewNode, NewLeaves, NewWorldState, AgentGoals))
|
||||||
{
|
{
|
||||||
@ -75,6 +66,17 @@ bool UGOAPAgent::BuildActionGraph(UActionNode* Parent, TArray<UActionNode*>& Suc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Log the plan
|
||||||
|
if (bFoundAPlan)
|
||||||
|
{
|
||||||
|
UE_LOG(LogTemp, Warning, TEXT("Found a plan!"));
|
||||||
|
// UActionNode* CurrentNode = SuccessfulLeaves[0];
|
||||||
|
// while (CurrentNode->Parent != nullptr)
|
||||||
|
// {
|
||||||
|
// UE_LOG(LogTemp, Warning, TEXT("%s"), *CurrentNode->Action->GetName());
|
||||||
|
// CurrentNode = CurrentNode->Parent;
|
||||||
|
// }
|
||||||
|
}
|
||||||
return bFoundAPlan;
|
return bFoundAPlan;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,13 +88,16 @@ void UGOAPAgent::TickComponent(float DeltaTime, ELevelTick TickType, FActorCompo
|
|||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
|
|
||||||
TArray<UGOAPAction*> UGOAPAgent::Plan(TMap<FString, int> WorldState, TMap<FString, int> AgentGoals)
|
TArray<UGOAPAction*> UGOAPAgent::Plan(UWorldState* WorldState, TMap<FString, int> AgentGoals)
|
||||||
{
|
{
|
||||||
TArray<UGOAPAction*> ActionPlan;
|
TArray<UGOAPAction*> ActionPlan;
|
||||||
UActionNode* RootActionNode = NewObject<UActionNode>();
|
UActionNode* RootActionNode = NewObject<UActionNode>();
|
||||||
RootActionNode->Init(nullptr, nullptr, WorldState, 0);
|
RootActionNode->Init(nullptr, nullptr, WorldState, 0);
|
||||||
TArray<UActionNode*> SuccessfulLeaves;
|
TArray<UActionNode*> SuccessfulLeaves;
|
||||||
|
|
||||||
|
SeenStates.Empty();
|
||||||
|
SeenStates.Add(WorldState);
|
||||||
|
|
||||||
if (BuildActionGraph(RootActionNode, SuccessfulLeaves, WorldState, AgentGoals))
|
if (BuildActionGraph(RootActionNode, SuccessfulLeaves, WorldState, AgentGoals))
|
||||||
{
|
{
|
||||||
//Find the cheapest leaf
|
//Find the cheapest leaf
|
||||||
@ -123,5 +128,7 @@ TArray<UGOAPAction*> UGOAPAgent::Plan(TMap<FString, int> WorldState, TMap<FStrin
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Remove the first action as it is null due to being the root node
|
||||||
|
ActionPlan.RemoveAt(0);
|
||||||
return ActionPlan;
|
return ActionPlan;
|
||||||
}
|
}
|
||||||
|
@ -4,8 +4,9 @@
|
|||||||
|
|
||||||
#include "CoreMinimal.h"
|
#include "CoreMinimal.h"
|
||||||
#include "GOAPAction.h"
|
#include "GOAPAction.h"
|
||||||
#include "COMP250_1_2101327_AI/TurnBasedCombatV2/TurnBaseCombatV2.h"
|
|
||||||
#include "Components/ActorComponent.h"
|
#include "Components/ActorComponent.h"
|
||||||
|
#include "Containers/UnrealString.h"
|
||||||
|
#include "WorldState.h"
|
||||||
#include "GOAPAgent.generated.h"
|
#include "GOAPAgent.generated.h"
|
||||||
|
|
||||||
UCLASS()
|
UCLASS()
|
||||||
@ -16,10 +17,10 @@ class UActionNode : public UObject
|
|||||||
public:
|
public:
|
||||||
UActionNode* Parent;
|
UActionNode* Parent;
|
||||||
UGOAPAction* Action;
|
UGOAPAction* Action;
|
||||||
TMap<FString, int> State;
|
UWorldState* State;
|
||||||
float Cost;
|
float Cost;
|
||||||
|
|
||||||
void Init(UActionNode* ParentNode, UGOAPAction* GOAPAction, TMap<FString, int> ProceduralState, float TotalCost)
|
void Init(UActionNode* ParentNode, UGOAPAction* GOAPAction, UWorldState* ProceduralState, float TotalCost)
|
||||||
{
|
{
|
||||||
Parent = ParentNode;
|
Parent = ParentNode;
|
||||||
Action = GOAPAction;
|
Action = GOAPAction;
|
||||||
@ -50,19 +51,14 @@ protected:
|
|||||||
// Called when the game starts
|
// Called when the game starts
|
||||||
virtual void BeginPlay() override;
|
virtual void BeginPlay() override;
|
||||||
|
|
||||||
UPROPERTY()
|
|
||||||
ATurnBaseCombatV2* CombatSystem;
|
|
||||||
|
|
||||||
UFUNCTION()
|
UFUNCTION()
|
||||||
bool BuildActionGraph(UActionNode* Parent, TArray<UActionNode*>& SuccessfulLeaves, TMap<FString, int> WorldState, TMap<FString, int> AgentGoals);
|
bool BuildActionGraph(UActionNode* Parent, TArray<UActionNode*>& SuccessfulLeaves, UWorldState* WorldState, TMap<FString, int> AgentGoals);
|
||||||
|
|
||||||
|
TSet<UWorldState*> SeenStates;
|
||||||
public:
|
public:
|
||||||
// Called every frame
|
// Called every frame
|
||||||
virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
|
virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
|
||||||
|
|
||||||
UFUNCTION()
|
UFUNCTION()
|
||||||
TArray<UGOAPAction*> Plan(TMap<FString, int> WorldState, TMap<FString, int> AgentGoals);
|
TArray<UGOAPAction*> Plan(UWorldState* WorldState, TMap<FString, int> AgentGoals);
|
||||||
|
|
||||||
UFUNCTION()
|
|
||||||
TMap<FString, int> GetWorldState();
|
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user