public GoapNode(GoapNode parent, GoapAction action, GoapStatus status, float cost) { parentNode = parent; goapAction = action; currentStatus = status; this.cost = cost; }
public List <GoapAction> Plan(Func <string, List <GoapAction> > actionPool, WorldState fromState, WorldState toState) { GoapNode start = new GoapNode(actionPool, null, fromState, this.npcType); GoapNode goal = new GoapNode(actionPool, null, toState, this.npcType); return(astar.GetPath(start, goal, GoapHeuristic, GoapCost).Select(goapNode => goapNode.data as GoapAction).ToList()); }
private void Clear() { this.parent = null; this.runningCost = 0; this.state = null; this.action = null; }
public GoapNode(GoapNode parent, float runningCost, List <KeyValuePair <string, object> > state, GoapAction action) { this.parent = parent; this.runningCost = runningCost; this.state = state; this.action = action; }
public GoapNode(GoapNode parent, float runningCost, Dictionary <string, object> state, GoapAction action) { this.parent = parent; this.runningCost = runningCost; this.state = state; this.action = action; }
private static int GoapHeuristic(AStarNode <GoapAction> a, AStarNode <GoapAction> b) { GoapNode aGoap = (GoapNode)a; GoapNode bGoap = (GoapNode)b; return(aGoap.worldState.Diff(bGoap.worldState)); }
public void ReInit(GoapNode parent, float runningCost, Dictionary <string, object> state, GoapAction action) { Clear(); this.parent = parent; this.runningCost = runningCost; this.state = state; this.action = action; }
public GoapNode( GoapNode parent, float runningCost, Dictionary <string, object> state, GoapAction action) { Parent = parent; RunningCost = runningCost; State = state; Action = action; }
private bool BuildGOAP(GoapNode parent, List <GoapNode> graph, List <GoapAction> usableActions, KeyValuePair <string, object> goal, int iteration) { List <KeyValuePair <string, object> > currentState; foreach (GoapAction action in usableActions) { if (IsStateSatisfied(action.preconditions, parent.state)) { if (action.GetType().Name.Equals("InventoryToCar")) { currentState = ApplyStateChange(parent.state); } else if (action.GetType().Name.Equals("CarToInventory")) { currentState = ApplyStateChange(parent.state, goal, action); } else { currentState = ApplyStateChange(parent.state, action.effects); } GoapNode node = new GoapNode(parent, parent.runningCost + action.cost, currentState, action); graph.Add(node); if (IsStateSatisfied(goal, currentState)) { return(true); } else { if (iteration >= 20) { iteration = 10; continue; } List <GoapAction> subset = new List <GoapAction>(); subset.AddRange(FindUsableActions(currentState, usableActions, goal, parent.runningCost + action.cost)); bool succ = BuildGOAP(node, graph, subset, goal, ++iteration); if (!succ) { continue; } else { return(true); } } } } return(false); }
/** * 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> ///如果找到至少一个解,则返回true。 ///可能的路径存储在叶子列表中。 每个节点都有一个 ///runningCost 值,其中最低成本将是最佳操作 ///序列。 ///</summary> private bool BuildGraph(GoapNode parent, List <GoapNode> leaves , HashSet <GoapAction> usableActions, KeyValuePair <string, bool> goal) { var foundOne = false; // go through each action available at this node and see if we can use it here //浏览此节点上的每个可用操作,看看我们是否可以在此处使用它 foreach (var 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 //将动作的效果应用于父状态 var currentState = PopulateState(parent.state, action.Effects); //Debug.Log(GoapAgent.prettyPrint(currentState)); var node = NodeManager.GetFreeNode(parent, parent.runningCost + action.GetCost(), parent.weight + action.GetWeight(), currentState, action); //force child.precondition in parent.effects or child.precondition is empty. //在parent.effects中强制child.precondition或child.precondition为空。 if (action.Preconditions.Count == 0 && parent.action != null || parent.action != null && !CondRelation(action.Preconditions, parent.action.Effects)) { continue; } if (FillGoal(goal, currentState)) { // we found a solution! //我们找到了解决方案! leaves.Add(node); foundOne = true; } else { // not at a solution yet, so test all the remaining actions and branch out the tree //还没有解决方案,所以测试所有剩余的动作并分支出树 var subset = ActionSubset(usableActions, action); var found = BuildGraph(node, leaves, subset, goal); if (found) { foundOne = true; } } } } return(foundOne); }
/// <summary> /// compare node /// 比较节点 /// </summary> /// <param name="cheapest"></param> /// <returns></returns> public bool BetterThen(GoapNode rh) { // return runningCost < rh.runningCost; if (weight > rh.weight && runningCost < rh.runningCost) { return(true); } if (weight < rh.weight && runningCost > rh.runningCost) { return(false); } //make weight > cost var better = (weight / rh.weight - 1) >= (runningCost / rh.runningCost - 1); return(better); }
/** * 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. */ private bool buildGraph(GoapNode parent, List <GoapNode> leaves , HashSet <GoapAction> usableActions, KeyValuePair <string, bool> goal) { var foundOne = false; // go through each action available at this node and see if we can use it here foreach (var 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 var currentState = populateState(parent.state, action.Effects); //Debug.Log(GoapAgent.prettyPrint(currentState)); var node = NodeManager.GetFreeNode(parent, parent.runningCost + action.GetCost(), parent.weight + action.GetWeight(), currentState, action); //force child.precondition in parent.effects or child.precondition is empty. if (action.Preconditions.Count == 0 && parent.action != null || parent.action != null && !CondRelation(action.Preconditions, parent.action.Effects)) { continue; } if (FillGoal(goal, currentState)) { // we found a solution! leaves.Add(node); foundOne = true; } else { // not at a solution yet, so test all the remaining actions and branch out the tree var subset = actionSubset(usableActions, action); var found = buildGraph(node, leaves, subset, goal); if (found) { foundOne = true; } } } } return(foundOne); }
public static GoapNode GetFreeNode(GoapNode parent, float runningCost, Dictionary <string, object> state, GoapAction action) { GoapNode free = null; if (_freeNodes.Count <= 0) { free = new GoapNode(parent, runningCost, state, action); } else { free = _freeNodes.Pop(); free.ReInit(parent, runningCost, state, action); } _usedNodes.Push(free); return(free); }
override public List <AStarNode <GoapAction> > GetNeighbours() { List <AStarNode <GoapAction> > neighbours = new List <AStarNode <GoapAction> >(); foreach (GoapAction action in this.actionPool(npcType)) { if (action.IsValid(this.worldState)) { WorldState neighbourWorldState = this.worldState.ApplyAction(action); if (this.worldState.Diff(neighbourWorldState) > 0) { GoapNode neighbour = new GoapNode(actionPool, action, neighbourWorldState, npcType); neighbours.Add(neighbour); } } } return(neighbours); }
/** * 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. */ private bool BuildGraph(GoapNode parent, List <GoapNode> leaves, HashSet <GoapAction> usableActions, Dictionary <string, object> 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, object> currentState = PopulateState(parent.state, action.effects); //Debug.Log(GoapAgent.prettyPrint(currentState)); GoapNode node = new GoapNode(parent, parent.runningCost + action.cost, currentState, action); if (InState(goal, currentState)) { // we found a solution! leaves.Add(node); foundOne = true; } else { // not at a solution yet, so test all the remaining actions and branch out the tree HashSet <GoapAction> subset = ActionSubset(usableActions, action); bool found = BuildGraph(node, leaves, subset, goal); if (found) { foundOne = true; } } } } return(foundOne); }
private List <GoapNode> DoPlan(List <GoapNode> leaves, List <GoapAction> actions, List <KeyValuePair <string, object> > worldState, KeyValuePair <string, object> goal) { foreach (GoapAction a in actions) { actionList.Add(a); a.DoReset(); } Debug.Log("Start World:" + GoapAgent.Display(worldState)); List <GoapAction> usableActions = FindUsableActions(worldState, new List <GoapAction>(), goal, 0); // build graph GoapNode start = new GoapNode(null, 0, worldState, null); bool success = BuildGOAP(start, leaves, usableActions, goal, 0); if (!success) { return(new List <GoapNode>()); } return(leaves); }
/** * 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); }
/** * 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, bool> worldState, KeyValuePair <string, bool> goal, IGoap goap) { // reset the actions so we can start fresh with them foreach (var a in availableActions) { a.doReset(); } // check what actions can run using their checkProceduralPrecondition var usableActions = NodeManager.GetFreeActionSet(); foreach (var a in availableActions) { if (a.checkProceduralPrecondition(agent, goap.GetBlackBoard())) { 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. var leaves = new List <GoapNode>(); // build graph var start = NodeManager.GetFreeNode(null, 0, 0, worldState, null); var success = buildGraph(start, leaves, usableActions, goal); if (!success) { // oh no, we didn't get a plan // Debug.Log("NO PLAN"); return(null); } // get the cheapest leaf GoapNode cheapest = null; foreach (var leaf in leaves) { if (cheapest == null) { cheapest = leaf; } else { if (leaf.BetterThen(cheapest)) { cheapest = leaf; } } } // get its node and work back through the parents var result = new List <GoapAction>(); var 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 var queue = new Queue <GoapAction>(); foreach (var a in result) { queue.Enqueue(a); } // hooray we have a plan! return(queue); }
// Compares the cost of 2 nodes public bool BetterThen(GoapNode other) { return(runningCost < other.runningCost); }
/// <summary> /// Creates an action plan based on a set of inital conditions /// and available actions /// </summary> /// <param name="initialConditions"> /// The initial world state to use for the planning. /// </param> /// <param name="goal"> /// The conditions that must be met at the end of the plan execution. /// </param> /// <param name="actions"> /// The actions that are available for use in the planning. /// </param> /// <returns> /// A list of GoapActions ready to be performed. /// </returns> public static List <GoapAction> CreatePlan( Dictionary <string, object> initialConditions, Dictionary <string, object> goal, GoapAction[] actions) { // Actions which are possible given the initial conditions HashSet <GoapAction> usableActions = new HashSet <GoapAction>(); // Reset all actions and get the // actions which are possible to // perform with the inital conditions foreach (GoapAction action in actions) { action.DoReset(); /* * foreach (var precondition in action.Preconditions) * { * if (initialConditions.ContainsKey(precondition.Key) && * initialConditions[precondition.Key] * .Equals(precondition.Value)) * { * usableActions.Add(action); * } * } */ usableActions.Add(action); } // Create a tree of possible plans. // Leaves represent the first action in a plan. List <GoapNode> leaves = new List <GoapNode>(); // Build the planning tree. GoapNode start = new GoapNode(null, 0, initialConditions, null); bool success = CreatePlanningTree(start, leaves, usableActions, goal); if (success) { // We successfully built a planning tree, now we need to // find the cheapest plan GoapNode cheapest = null; foreach (GoapNode leaf in leaves) { if (cheapest == null || leaf.RunningCost < cheapest.RunningCost) { cheapest = leaf; } } // Work back through the leaf's parents and reconstruct the path List <GoapAction> plan = new List <GoapAction>(); GoapNode currentNode = cheapest; while (currentNode != null) { if (currentNode.Action != null) { plan.Insert(0, currentNode.Action); } currentNode = currentNode.Parent; } return(plan); } else { // No plan return(null); } }
/** * 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. * 计划可以实现目标的行动顺序。 * 如果找不到计划,或者操作列表,则返回null * 必须按顺序执行才能实现目标。 */ ///<summary> ///计划 ///</summary> public Queue <GoapAction> Plan(GameObject agent, HashSet <GoapAction> availableActions, Dictionary <string, bool> worldState, KeyValuePair <string, bool> goal, IGoap goap) { // reset the actions so we can start fresh with them //重置动作,以便我们可以重新开始 foreach (var a in availableActions) { a.doReset(); } // check what actions can run using their checkProceduralPrecondition //使用检查程序前置条件检查可以运行的操作 var usableActions = NodeManager.GetFreeActionSet(); foreach (var a in availableActions) { if (a.CheckProceduralPrecondition(agent, goap.GetBlackBoard())) { usableActions.Add(a); } } // we now have all actions that can run, stored in usableActions //我们现在拥有可以运行的所有操作,存储在usefulActions中 // build up the tree and record the leaf nodes that provide a solution to the goal. //构建树并记录提供目标解决方案的节点。 var leaves = new List <GoapNode>(); // build graph //构建图表 var start = NodeManager.GetFreeNode(null, 0, 0, worldState, null); //构建图 var success = BuildGraph(start, leaves, usableActions, goal); if (!success) { // oh no, we didn't get a plan //不,我们没有得到一个计划 // Debug.Log("NO PLAN"); return(null); } // get the cheapest leaf //得到最便宜的节点 GoapNode cheapest = null; foreach (var leaf in leaves) { if (cheapest == null) { cheapest = leaf; } else { if (leaf.BetterThen(cheapest)) { cheapest = leaf; } } } // get its node and work back through the parents //获取其节点并通过父节点返回 var result = new List <GoapAction>(); var 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 //我们现在按正确的顺序拥有此操作列表 var queue = new Queue <GoapAction>(); foreach (var a in result) { queue.Enqueue(a); } // hooray we have a plan! //万岁,我们有一个计划! return(queue); }
/** * 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(HashSet <GoapAction> availableActions, Dictionary <string, object> worldState, Dictionary <string, object> goal) { // reset the actions so we can start fresh with them foreach (GoapAction a in availableActions) { a.Reset(); } // check what actions can run using their checkProceduralPrecondition HashSet <GoapAction> usableActions = new HashSet <GoapAction> (); foreach (GoapAction a in availableActions) { if (a.CheckProceduralPrecondition()) { 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 = new GoapNode(null, 0, worldState, null); bool success = BuildGraph(start, leaves, usableActions, goal); if (!success) { // oh no, we didn't get a plan return(null); } // get the cheapest leaf GoapNode cheapest = null; foreach (GoapNode leaf in leaves) { if (cheapest == null) { cheapest = leaf; } else { if (leaf.runningCost < cheapest.runningCost) { 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; } // we now have this action list in correct order Queue <GoapAction> queue = new Queue <GoapAction> (); foreach (GoapAction a in result) { queue.Enqueue(a); } // hooray we have a plan! return(queue); }
public GoapNode(GoapNode parent, float runningCost, Dictionary <string, object> state, GoapAction action) { ID = MaxID++; ReInit(parent, runningCost, state, action); }
/// <summary> /// Creates a goap planning tree. /// </summary> /// <param name="parent">The node we're working down from.</param> /// <param name="leaves"></param> /// <param name="usableActions"></param> /// <param name="Dictionary<string"></param> /// <param name="goalState"></param> /// <returns>True if success, false otherwise.</returns> private static bool CreatePlanningTree( GoapNode parent, List <GoapNode> leaves, HashSet <GoapAction> usableActions, Dictionary <string, object> goalState) { bool success = false; // Go through each action and see if it can be used foreach (GoapAction action in usableActions) { if (_debugEnabled) { // Check if the action us usable given the parent's state if (parent.Action != null) { Debug.Log(parent.Action.GetType().Name); } else { Debug.Log("No parent action."); } Debug.Log("\t->" + action.GetType().Name); } bool canUseAction = true; foreach (var precondition in action.Preconditions) { if (_debugEnabled) { Debug.Log("\t\t" + precondition.Key + " must be " + precondition.Value); } if (parent.State.ContainsKey(precondition.Key)) { object parentValue = parent.State[precondition.Key]; if (!parentValue.Equals(precondition.Value)) { canUseAction = false; } if (_debugEnabled) { Debug.Log("\t\t" + precondition.Key + " was " + parentValue); } } else { if (_debugEnabled) { Debug.Log( "\t\t" + precondition.Key + " was not present." ); } canUseAction = false; } } if (_debugEnabled) { Debug.Log("\t\tCan use " + canUseAction); } if (canUseAction) { // Set current state to be // parent's state + the action's effects var currentState = new Dictionary <string, object>(); foreach (var key in parent.State.Keys) { currentState[key] = parent.State[key]; } foreach (var effect in action.Effects) { currentState[effect.Key] = effect.Value; if (_debugEnabled) { Debug.Log("\t\tEffect: " + effect.Key + " " + currentState[effect.Key]); } } GoapNode node = new GoapNode( parent, parent.RunningCost + action.Cost, currentState, action ); bool isDone = true; foreach (var goal in goalState) { if (currentState.ContainsKey(goal.Key)) { if (!currentState[goal.Key].Equals(goal.Value)) { isDone = false; } } else { isDone = false; } } if (isDone) { if (_debugEnabled) { Debug.Log("--------- Done! ---------"); } leaves.Add(node); success = true; } else { var subsetActions = new HashSet <GoapAction>(); if (_debugEnabled) { Debug.Log("\t\t\tSubset actions"); } foreach (var subsetAction in usableActions) { if (subsetAction != action) { subsetActions.Add(subsetAction); if (_debugEnabled) { Debug.Log("\t\t\t\tAdded " + subsetAction.GetType().Name); } } } if (_debugEnabled) { foreach (var subsetAction in subsetActions) { Debug.Log("\t\t\t\tContains " + subsetAction.GetType().Name); } Debug.Log("\t\t\tCreate subset"); } bool subsetSuccess = CreatePlanningTree( node, leaves, subsetActions, goalState ); if (_debugEnabled) { Debug.Log("\t\t\t\t\t\t" + subsetSuccess); } if (subsetSuccess) { success = true; } } } } return(success); }