/// <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);
        }
예제 #2
0
        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);
        }
예제 #3
0
        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);
        }
예제 #4
0
        /// <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);
        }