Added Comments to GOAP Functions

This commit is contained in:
Philip W 2023-03-23 01:11:25 +00:00
parent 4639a4d1ac
commit 2b43f174a2
3 changed files with 48 additions and 18 deletions

View File

@ -3,6 +3,11 @@
#include "GOAPAction.h"
/**
* @brief Checks if the preconditions are met in the world state given
* @param WorldState A pointer to the world state to check
* @return True if the preconditions are met and false if not
*/
bool UGOAPAction::CheckPreConditions(UWorldState* WorldState)
{
for (TPair<FString, int> PreCondition : PreConditions)
@ -15,6 +20,11 @@ bool UGOAPAction::CheckPreConditions(UWorldState* WorldState)
return true;
}
/**
* @brief Applies the effects of the action to the world state given
* @param WorldState A pointer to the world state to apply the effects to
* @return A pointer to the new world state
*/
UWorldState* UGOAPAction::ApplyEffects(UWorldState* WorldState)
{
UWorldState* NewWorldState = NewObject<UWorldState>();
@ -29,6 +39,10 @@ UWorldState* UGOAPAction::ApplyEffects(UWorldState* WorldState)
return NewWorldState;
}
/**
* @brief Performs the action
* @return A map of the effects of the action
*/
TMap<FString, int> UGOAPAction::Perform()
{
return Effects;

View File

@ -32,10 +32,18 @@ void UGOAPAgent::BeginPlay()
AvailableActions.Add(Action);
}
//Sort AvailableActions by cost
//Sorts AvailableActions by cost to optimise the search by choosing the cheapest action first
AvailableActions.Sort([](const UGOAPAction& A, const UGOAPAction& B) { return A.ActionCost < B.ActionCost; });
}
/**
* @brief Recursive function to build a tree of possible actions
* @param Parent The parent node containing the previous action or null if this is the root node
* @param SuccessfulLeaves The array of nodes that lead to a successful goal state
* @param WorldState The state of the world with it's applicable effects applied
* @param AgentGoals The goals of the agent
* @return True if a plan was found and false if not
*/
bool UGOAPAgent::BuildActionGraph(UActionNode* Parent, TArray<UActionNode*>& SuccessfulLeaves, UWorldState* WorldState, TMap<FString, int> AgentGoals)
{
bool bFoundAPlan = false;
@ -48,12 +56,24 @@ bool UGOAPAgent::BuildActionGraph(UActionNode* Parent, TArray<UActionNode*>& Suc
UActionNode* NewNode = NewObject<UActionNode>();
NewNode->Init(Parent, Action, NewWorldState, Parent->Cost + Action->ActionCost);
if (NewWorldState->State["PlayerHealth"] <= 0)
//Check if the new state meets the agent's goals
bool bMetGoals = true;
for (TTuple<FString, int> Goal : AgentGoals)
{
if (NewWorldState->State[Goal.Key] > Goal.Value)
{
bMetGoals = false;
break;
}
}
if (bMetGoals)
{
SuccessfulLeaves.Add(NewNode);
bFoundAPlan = true;
}
else if (!SeenStates.Contains(NewWorldState) && !bFoundAPlan)
//Check if the new state has been seen before and if a plan has been found otherwise recurse
if (!SeenStates.Contains(NewWorldState) && !bFoundAPlan)
{
SeenStates.Add(NewWorldState);
TArray<UActionNode*> NewLeaves;
@ -66,17 +86,6 @@ 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;
}
@ -88,6 +97,13 @@ void UGOAPAgent::TickComponent(float DeltaTime, ELevelTick TickType, FActorCompo
// ...
}
/**
* @brief Creates a plan of actions to achieve the agent's goals
* @param WorldState The current state of the world
* @param AgentGoals The goals of the agent
* @return An array of actions to achieve the agent's goals efficiently with it's current resources or
* an empty array if no plan was found
*/
TArray<UGOAPAction*> UGOAPAgent::Plan(UWorldState* WorldState, TMap<FString, int> AgentGoals)
{
TArray<UGOAPAction*> ActionPlan;
@ -128,7 +144,7 @@ TArray<UGOAPAction*> UGOAPAgent::Plan(UWorldState* WorldState, TMap<FString, int
}
}
//Remove the first action as it is null due to being the root node
//Remove the first action as it's action is null due to being the root node
ActionPlan.RemoveAt(0);
return ActionPlan;
}

View File

@ -22,7 +22,7 @@ ATurnBaseCombatV2::ATurnBaseCombatV2()
static ConstructorHelpers::FClassFinder<UUserWidget> HUDWidgetClass(TEXT("/Game/Blueprints/Combat_UI/Combat_UI"));
HUDWidget = HUDWidgetClass.Class;
static ConstructorHelpers::FClassFinder<UUserWidget> ActionItemWidgetClass(TEXT("/Game/Blueprints/Combat_UI/ActionItem"));
ActionPlanItemWidget = ActionItemWidgetClass.Class;
ActionPlanItemWidget = ActionItemWidgetClass.Class;
static ConstructorHelpers::FClassFinder<UStatusEffect> StatusEffectThornsClassFinder(TEXT("/Game/Blueprints/StatusEffects/BP_Thorns"));
ThornsStatusEffect = StatusEffectThornsClassFinder.Class;
static ConstructorHelpers::FClassFinder<UStatusEffect> StatusEffectDotClassFinder(TEXT("/Game/Blueprints/StatusEffects/BP_DamageOverTime"));
@ -486,7 +486,7 @@ void ATurnBaseCombatV2::EnemyTurn()
EnemyIroquoidResource -= Effect.Value;
}
}
EnemyActionPlan.RemoveAt(0);
UpdateResourceBars();
}
@ -534,7 +534,7 @@ void ATurnBaseCombatV2::StealButtonOnClick()
{
StealButton->SetIsEnabled(false);
ClearActionPlanWidget();
TArray<int*> Resources = {&EnemyProbertiumResource, &EnemyEisResource, &EnemyAzosResource, &EnemyIroquoidResource};
TArray Resources = {&EnemyProbertiumResource, &EnemyEisResource, &EnemyAzosResource, &EnemyIroquoidResource};
Resources.Sort([](const int& A, const int& B) { return A > B; });
for (int* Resource : Resources)
{