/// <summary> /// A* forward search for a plan that satisfies the given goal. /// </summary> /// <returns>Returns null if a plan could not be found, or a list of the /// actions that must be performed, in order.</returns> public static Queue <ITransition> Plan( GoapAgent agent, WorldGoal goal) { var worldState = WorldState.Borrow(); worldState[agent] = agent.GetState(); var regressiveSearchGoal = RegressiveSearchWorldGoal.Borrow(goal); DebugUtils.Assert(worldState[agent].ContainsKey("x") && worldState[agent].ContainsKey("y") && worldState[agent].ContainsKey("z"), "Agent's state must contain his position as 'x' and 'y' keys"); var path = AStarSearch.Search(agent, regressiveSearchGoal, worldState, true); worldState.ReturnSelf(); GoapAction.WithContext.ReportLeaks(); State.ReportLeaks(); WorldState.ReportLeaks(); WorldGoal.ReportLeaks(); RegressiveSearchWorldGoal.ReportLeaks(); WorldEffects.ReportLeaks(); return(path); }
protected virtual bool CanDoNow(GoapAgent agent, IStateful target) { var worldState = WorldState.pool.Borrow(); worldState.Clear(); worldState[agent] = agent.GetState(); worldState[target] = target.GetState(); var conditions = GetDependentPreconditions(agent, target); bool result = GoapPlanner.DoConditionsApplyToWorld(conditions, worldState); WorldState.pool.Return(worldState); return(result); }
protected virtual bool CanDoNow(GoapAgent agent, IStateful target) { var worldState = WorldState.Borrow(); worldState[agent] = agent.GetState(); worldState[target] = target.GetState(); // Since the action is a part of the plan, its preconditions on the agent // should apply. var doesApply = worldState.IsGoalState(GetIndependentPreconditions(agent)); // NOTE: If the agent's state is volatile and can change outside of the // agent's plan, comment out this assertion. DebugUtils.AssertWarning( doesApply, "WARNING: Possible bug in definition of " + name + ". The agent " + agent.name + " planned to do it but now its state does not allow it"); // Need to check that the target's state still apply to the preconditions // defined by the action. doesApply = doesApply && worldState.IsGoalState(GetDependentPreconditions(agent, target)); worldState.ReturnSelf(); return(doesApply); }
/// <summary> /// A* forward search for a plan that satisfies the given goal. /// </summary> /// <returns>Returns null if a plan could not be found, or a list of the /// actions that must be performed, in order.</returns> public static Queue <GoapAction.WithContext> Plan( GoapAgent agent, List <GoapAction> availableActions, WorldGoal goal) { var exploredNodes = new Dictionary <WorldState, Node> (WorldStateComparer.instance); var closedSet = new HashSet <WorldState> (WorldStateComparer.instance); var openSet = new FastPriorityQueue <Node> (MAX_FRINGE_NODES); var currentNode = Node.pool.Borrow(); currentNode.Init(null, 0f, goal, null, null); // currentNode.position = Vector2.zero; currentNode.position = (agent as Component).transform.position; openSet.Enqueue(currentNode, 0f); int iterations = 0; while (openSet.Count > 0 && iterations < MAX_FRINGE_NODES - 10) { iterations++; currentNode = openSet.Dequeue(); //TODO: delete print //Debug.Log ("current world goal: " + GoapAgent.PrettyPrint(currentNode.goal)); if (DoConditionsApply(currentNode.goal[agent], agent.GetState())) { DebugUtils.Log("Selected plan with cost: " + currentNode.Score); var plan = UnwrapPlan(currentNode); //DebugUtils.Log("the plan: " + GoapAgent.PrettyPrint(plan)); // Return all nodes. Node.pool.ReturnAll(); // Check for leaks in the pools: //DebugUtils.LogError("Nodes: " + Node.pool.Count); //DebugUtils.LogError("WithContext: " + GoapAction.WithContext.pool.Count); //DebugUtils.LogError("WorldState: " + WorldState.pool.Count); return(plan); } foreach (GoapAction action in availableActions) { //TODO: delete print //Debug.Log("considering " + action.name); WorldGoal possibleChildGoal = action.reverseApplyToWorldGoal(currentNode.goal); //Debug.Log ("new goal will be: " + GoapAgent.PrettyPrint(possibleChildGoal)); if (agent.GetState().isGoalCloser(currentNode.goal, possibleChildGoal)) { List <IStateful> targets = action.GetAllTargets(agent); // No targets, move to next action if (targets.Count == 0) { continue; } float minCost = 99999f; float tempCost = 0f; IStateful closestTarget = null; Vector2 newPosition = currentNode.position; foreach (var target in targets) { //DebugUtils.Log ("targets..."); //TODO: check target preconds, make sure this works if (goal.ContainsKey(target)) { if (!DoConditionsApply(goal [target], target.GetPerceivedState())) { continue; } } if (action.RequiresInRange()) { tempCost = action.CalculateCost(currentNode.position, target); if (tempCost < minCost) { minCost = tempCost; closestTarget = target; newPosition = (target as Component).transform.position; DebugUtils.Log("minCost: " + minCost); DebugUtils.Log("closestTarget: " + closestTarget); } //DebugUtils.Log ("calculating tempCost"); } else { closestTarget = target; tempCost = 9999; DebugUtils.Log("+++ closestTarget: " + closestTarget); break; } } float cost = currentNode.runningCost + action.workDuration + tempCost; Node newChiledNode = Node.pool.Borrow(); DebugUtils.Log("*** closestTarget: " + closestTarget); newChiledNode.Init(currentNode, cost, possibleChildGoal, action, closestTarget); newChiledNode.position = newPosition; openSet.Enqueue(newChiledNode, newChiledNode.runningCost); } //TODO: delete 'else' scope else { //DebugUtils.Log (action.name + " doesnt improve goal"); } } } //TODO: return plan failed #yoel return(null); }