public List <PlannerNode <TKey, TValue> > GetNeighbours(PlannerNode <TKey, TValue> _baseNode) { m_NeighbourNodes.Clear(); WorldStateModifier <TKey, TValue> basePreconditions = _baseNode.Action?.GetPreconditions(); WorldState <TKey, TValue> worldStateAtBaseNode = _baseNode.GetWorldStateAtNode(); Goal <TKey, TValue> goalWorldStateAtBaseNode = _baseNode.GetGoalWorldStateAtNode(); WorldState <TKey, TValue> remainingGoals = goalWorldStateAtBaseNode - worldStateAtBaseNode; // We implement regressive A* for GOAP by chaining action preconditions to action effects until all preconditions are fulfilled. // For this planner, neighbours are nodes that fulfil any of the remaining goals of the base node without conflicting with any of its preconditions. foreach (IAction <TKey, TValue> possibleAction in m_CurrentAgent.GetActionSet()) { var effects = possibleAction.GetEffects(); if (!effects.ContainsAny(remainingGoals)) { continue; } if (effects.ConflictsAny(basePreconditions)) { continue; } PlannerNode <TKey, TValue> plannerNode = GetAvailablePlannerNode(); plannerNode.Init(possibleAction); plannerNode.CalculateWorldStateAtNode(worldStateAtBaseNode); plannerNode.CalculateGoalWorldStateAtNode(goalWorldStateAtBaseNode); bool foundInUsed = false; foreach (PlannerNode <TKey, TValue> usedNode in m_UsedNodes) { if (usedNode.Equals(plannerNode)) { plannerNode = usedNode; foundInUsed = true; break; } } m_NeighbourNodes.Add(plannerNode); if (!foundInUsed) { m_UsedNodes.Add(plannerNode); } } return(m_NeighbourNodes); }
public GoalPlanPair <TKey, TValue> GenerateGoalPlanPairForAgent(IAgent <TKey, TValue> _agent) { m_CurrentAgent = _agent; Stack <PlannerNode <TKey, TValue> > foundPath = null; bool newGoalBetterThanActiveGoal = false; m_GoalPlanPair.GoalInstance = null; m_GoalPlanPair.PlanInstance = null; for (var goalQueue = m_CurrentAgent.CalculateSortedGoals(); goalQueue.Count > 0;) { SortableGoal <TKey, TValue> goal = goalQueue.Dequeue(); PlannerNode <TKey, TValue> agentNode = new PlannerNode <TKey, TValue>(); agentNode.CalculateWorldStateAtNode(_agent.GetWorkingMemory()); agentNode.CalculateGoalWorldStateAtNode(goal); foundPath = m_Pathfinder.FindPath(agentNode, null); if (foundPath != null && foundPath.Count > 0) { newGoalBetterThanActiveGoal = _agent.IsGoalBetterThanActiveGoal(goal); if (newGoalBetterThanActiveGoal) { m_GoalPlanPair.GoalInstance = goal; #if UNITY_EDITOR _agent.CreatePlanHierarchy(foundPath.Last(), m_Pathfinder.GetOpenNodes(), m_Pathfinder.GetClosedNodes()); #endif } break; } } m_GoalPlanPair.PlanInstance = new Plan <TKey, TValue>(); if (newGoalBetterThanActiveGoal && foundPath != null) { foreach (PlannerNode <TKey, TValue> pathNode in foundPath) { if (pathNode.Action != null) { m_GoalPlanPair.PlanInstance.Push(pathNode.Action); } } } m_UsedNodes.Clear(); RecycleUsedNodes(); return(m_GoalPlanPair); }