diff --git a/COMP250_1_2101327_AI/Source/COMP250_1_2101327_AI/GOAP/GOAPAction.cpp b/COMP250_1_2101327_AI/Source/COMP250_1_2101327_AI/GOAP/GOAPAction.cpp index 3026de0..65128ac 100644 --- a/COMP250_1_2101327_AI/Source/COMP250_1_2101327_AI/GOAP/GOAPAction.cpp +++ b/COMP250_1_2101327_AI/Source/COMP250_1_2101327_AI/GOAP/GOAPAction.cpp @@ -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 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(); @@ -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 UGOAPAction::Perform() { return Effects; diff --git a/COMP250_1_2101327_AI/Source/COMP250_1_2101327_AI/GOAP/GOAPAgent.cpp b/COMP250_1_2101327_AI/Source/COMP250_1_2101327_AI/GOAP/GOAPAgent.cpp index 0666c12..81cf8bd 100644 --- a/COMP250_1_2101327_AI/Source/COMP250_1_2101327_AI/GOAP/GOAPAgent.cpp +++ b/COMP250_1_2101327_AI/Source/COMP250_1_2101327_AI/GOAP/GOAPAgent.cpp @@ -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& SuccessfulLeaves, UWorldState* WorldState, TMap AgentGoals) { bool bFoundAPlan = false; @@ -48,12 +56,24 @@ bool UGOAPAgent::BuildActionGraph(UActionNode* Parent, TArray& Suc UActionNode* NewNode = NewObject(); 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 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 NewLeaves; @@ -66,17 +86,6 @@ bool UGOAPAgent::BuildActionGraph(UActionNode* Parent, TArray& 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 UGOAPAgent::Plan(UWorldState* WorldState, TMap AgentGoals) { TArray ActionPlan; @@ -128,7 +144,7 @@ TArray UGOAPAgent::Plan(UWorldState* WorldState, TMap HUDWidgetClass(TEXT("/Game/Blueprints/Combat_UI/Combat_UI")); HUDWidget = HUDWidgetClass.Class; static ConstructorHelpers::FClassFinder ActionItemWidgetClass(TEXT("/Game/Blueprints/Combat_UI/ActionItem")); - ActionPlanItemWidget = ActionItemWidgetClass.Class; + ActionPlanItemWidget = ActionItemWidgetClass.Class; static ConstructorHelpers::FClassFinder StatusEffectThornsClassFinder(TEXT("/Game/Blueprints/StatusEffects/BP_Thorns")); ThornsStatusEffect = StatusEffectThornsClassFinder.Class; static ConstructorHelpers::FClassFinder 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 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) {