示例#1
0
        /// <summary>
        /// Apply the action's effects to the parent state.
        /// </summary>
        /// <param name="actionEffects">Current state</param>
        /// <param name="parentState">State change</param>
        private Dictionary <string, bool> PopulateState(Dictionary <string, bool> actionEffects, Dictionary <string, bool> parentState)
        {
            Dictionary <string, bool> state = GOAPPlannerHelper.GetFreeState();

            state.Clear();

            foreach (KeyValuePair <string, bool> s in actionEffects)
            {
                state.Add(s.Key, s.Value);
            }

            foreach (KeyValuePair <string, bool> change in parentState)
            {
                // If key exists in the current state, update the value.
                if (state.ContainsKey(change.Key))
                {
                    state[change.Key] = change.Value;
                }
                else
                {
                    state.Add(change.Key, change.Value);
                }
            }

            return(state);
        }
示例#2
0
        /// <summary>
        /// Creates a subset of the actions excluding the actionToRemove. Creates a new set.
        /// </summary>
        /// <param name="actions">Usuable actions</param>
        /// <param name="actionToRemove">Action to exclude from this branch</param>
        private HashSet <GOAPAction> ActionSubset(HashSet <GOAPAction> actions, GOAPAction actionToRemove)
        {
            HashSet <GOAPAction> subset = GOAPPlannerHelper.GetFreeActionSet();

            foreach (GOAPAction action in actions)
            {
                if (!action.Equals(actionToRemove))
                {
                    subset.Add(action);
                }
            }

            return(subset);
        }
示例#3
0
        /// <summary>
        /// Builds the plan of actions. Returns true if at least one solution was found.
        /// The possible paths are stored in the leaves list. Each leaf has a 'runningCost' value where the lowest cost will be the best action sequence.
        /// </summary>
        /// <param name="parent">Parent node</param>
        /// <param name="leaves">List of nodes with possible paths</param>
        /// <param name="usableActions">Actions available to the GOAPAgent</param>
        /// <param name="goal">Goal that GOAPAgent is trying to achieve</param>
        private bool BuildGraph(GOAPNode parent, List <GOAPNode> leaves, HashSet <GOAPAction> usableActions, KeyValuePair <string, bool> goal)
        {
            bool foundOne = false;

            // Go through each action available at this node and see if we can use it here.
            foreach (GOAPAction action in usableActions)
            {
                // If the parent state has the conditions for this action's preconditions, we can use it here.
                if (InState(action.Preconditions, parent._state))
                {
                    // Apply the action's effects to the parent state.
                    Dictionary <string, bool> currentState = PopulateState(parent._state, action.Effects);
                    GOAPNode node = GOAPPlannerHelper.GetFreeNode(parent, parent._runningCost + action.GetCost(), parent._weight + action.GetWeight(), currentState, action);

                    // If there's no match between child's precondition and parent's effects or child's precondition is empty.
                    if (parent._action != null && (action.Preconditions.Count == 0 || !CondRelation(action.Preconditions, parent._action.Effects)))
                    {
                        continue;
                    }

                    if (GoalInState(goal, currentState))
                    {
                        // There is a solution.
                        leaves.Add(node);
                        foundOne = true;
                    }
                    else
                    {
                        // Not at a solution yet, so we're testing all of the remaining actions and branching out the tree.
                        HashSet <GOAPAction> subset = ActionSubset(usableActions, action);
                        bool found = BuildGraph(node, leaves, subset, goal);
                        if (found)
                        {
                            foundOne = true;
                        }
                    }
                }
            }

            return(foundOne);
        }
示例#4
0
        /// <summary>
        /// Plans what sequence of actions can fulfill the goal.
        /// Returns null if a plan could not be found, or a list of the actions that must be performed, in order, to fulfill the goal.
        /// </summary>
        /// <param name="agent">GOAPAgent</param>
        /// <param name="availableActions">Actions that can be performed</param>
        /// <param name="worldState">Starting world state</param>
        /// <param name="goal">Goal that GOAPAgent is trying to achieve</param>
        /// <param name="AIAgent">Implementing class that provides our world data and listens to feedback on planning</param>
        public Queue <GOAPAction> Plan(GameObject agent,
                                       HashSet <GOAPAction> availableActions,
                                       Dictionary <string, bool> worldState,
                                       KeyValuePair <string, bool> goal,
                                       IAIAgent AIAgent)
        {
            // Reset all of the actions that can be performed.
            foreach (GOAPAction action in availableActions)
            {
                action.DoReset();
            }

            // Loops through the available actions and adds the ones that can be performed to a list.
            HashSet <GOAPAction> usableActions = GOAPPlannerHelper.GetFreeActionSet();

            foreach (GOAPAction action in availableActions)
            {
                // If the the action can be performed.
                if (action.CheckProceduralPrecondition(agent, AIAgent.DataHolder))
                {
                    usableActions.Add(action);
                }
            }

            // Create a "tree" of actions that will lead to the wanted goal.
            List <GOAPNode> leaves  = new List <GOAPNode>();
            GOAPNode        start   = GOAPPlannerHelper.GetFreeNode(null, 0, 0, worldState, null);
            bool            success = BuildGraph(start, leaves, usableActions, goal);

            if (!success)
            {
                return(null);
            }

            // Find the cheapest plan of action out of each generated plan.
            GOAPNode cheapest = null;

            foreach (GOAPNode leaf in leaves)
            {
                if (cheapest == null)
                {
                    cheapest = leaf;
                }
                else
                {
                    if (leaf.BetterThen(cheapest))
                    {
                        cheapest = leaf;
                    }
                }
            }

            // Get its node and work back through the parents.
            List <GOAPAction> result = new List <GOAPAction>();
            GOAPNode          n      = cheapest;

            while (n != null)
            {
                if (n._action != null)
                {
                    // Insert the action in the front.
                    result.Insert(0, n._action);
                }
                n = n._parent;
            }

            // Clean up after we're done.
            GOAPPlannerHelper.Release();

            // Create a final plan to follow.
            Queue <GOAPAction> finalQueue = new Queue <GOAPAction>();

            foreach (GOAPAction action in result)
            {
                finalQueue.Enqueue(action);
            }

            return(finalQueue);
        }