private void CreatePerformActionState() { performActionState = (fsm, gameObj) => { // perform the action if (!HasActionPlan()) { // no actions to perform Debug.Log("<color=red>Done actions</color>"); fsm.PopState(); fsm.PushState(idleState); dataProvider.ActionsFinished(); return; } GoapAction action = currentActions.Peek(); if (action.IsDone()) { // the action is done. Remove it so we can perform the next one currentActions.Dequeue(); } if (HasActionPlan()) { // perform the next action action = currentActions.Peek(); bool inRange = action.RequiresInRange() ? action.IsInRange() : true; if (inRange) { // we are in range, so perform the action bool success = action.Perform(gameObj, dataProvider.GetMemory()); if (!success) { // action failed, we need to plan again fsm.PopState(); fsm.PushState(idleState); dataProvider.PlanAborted(action); } } else { // we need to move there first // push moveTo state fsm.PushState(moveToState); } } else { // no actions left, move to Plan state fsm.PopState(); fsm.PushState(idleState); dataProvider.ActionsFinished(); } }; }
/** * Plan 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. */ public Queue <GoapAction> Plan(GameObject agent, HashSet <GoapAction> availableActions, Dictionary <string, object> worldState, KeyValuePair <string, object> goal, IGoap goap) { // reset the actions so we can start fresh with them foreach (GoapAction a in availableActions) { a.DoReset(); } // check what actions can run using their checkProceduralPrecondition HashSet <GoapAction> usableActions = NodeManager.GetFreeActionSet(); foreach (GoapAction a in availableActions) { if (a.CheckProceduralPrecondition(agent, goap.GetMemory())) { usableActions.Add(a); } } // we now have all actions that can run, stored in usableActions // build up the tree and record the leaf nodes that provide a solution to the goal. List <GoapNode> leaves = new List <GoapNode>(); // build graph GoapNode start = NodeManager.GetFreeNode(null, 0, worldState, null); bool success = BuildGraph(start, leaves, usableActions, goal); if (!success) { // oh no, we didn't get a plan Debug.Log("[" + agent.name + "] " + "NO PLAN"); return(null); } // get the cheapest leaf 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) { result.Insert(0, n.action); // insert the action in the front } n = n.parent; } NodeManager.Release(); // we now have this action list in correct order Queue <GoapAction> queue = new Queue <GoapAction>(); foreach (GoapAction a in result) { queue.Enqueue(a); } // Builds a shortest way for many actions //for (int i = 1; i < result.Count; i++) //{ // GoapAction a = result[i]; // a.CheckDistance(result[i-1].target, goap.GetMemory()); //} // hooray we have a plan! return(queue); }