public GOAPNode(GOAPNode _parent, float _runningCost, Dictionary <string, bool> _state, GOAPAction _action) { parent = _parent; runningCost = _runningCost; state = _state; action = _action; }
public GOAPNode(GOAPNode p, GOAPAction a, Dictionary <Condition, object> s, float c) { parent = p; action = a; state = s; costSoFar = c; }
//Currently using DFS, goal to switch to A* private void BuildGraph(GOAPNode root, HashSet <GOAPAction> usableActions, Dictionary <Condition, object> goal, int searchDepth, List <GOAPNode> solutionNodes) { if (searchDepth > MAX_DEPTH) { return; } //O(N^2) foreach (GOAPAction action in usableActions) { if (usedActions.Contains(action)) { continue; } if (action.CheckPreConditions(root.state)) { Dictionary <Condition, object> newState = action.ApplyPostConditionsToState(root.state); GOAPNode node = new GOAPNode(root, action, newState, root.costSoFar + action.cost); if (GoalFromState(goal, newState)) { solutionNodes.Add(node); } else { usedActions.Add(action); BuildGraph(node, usableActions, goal, searchDepth + 1, solutionNodes); usedActions.Remove(action); } } } }
public void ShouldBeIndependentOfClone() { GOAPNode original = new GOAPNode(new WorldState(ws), null); GOAPNode clone = (GOAPNode)original.Clone(); clone.WorldState.SetToken("a", !(bool)original.WorldState.GetValue("a")); Assert.AreNotEqual(clone.WorldState.GetValue("a"), original.WorldState.GetValue("a")); }
public Queue <GOAPAction> CreatePlan(NPC agent, Dictionary <Condition, object> goal) { Dictionary <Condition, object> currentNPCState = agent.GetNPCState(); //Check to see if goal is already fulfilled if (GoalFromState(goal, currentNPCState)) { return(null); } HashSet <GOAPAction> usableActions = GetUsableActions(agent.AllActions, currentNPCState); List <GOAPNode> solutionNodes = new List <GOAPNode>(); GOAPNode root = new GOAPNode(null, null, currentNPCState, 0); List <GOAPNode> nodes = new List <GOAPNode>(); BuildGraph(root, agent.AllActions, goal, 0, solutionNodes); if (solutionNodes.Count == 0) { return(null); } //Found at least one solution float minCost = solutionNodes[0].costSoFar; GOAPNode cheapestNode = solutionNodes[0]; //Find the cheapest(best) solution for (int i = 1; i < solutionNodes.Count; i++) { cheapestNode = solutionNodes[i].costSoFar < minCost ? solutionNodes[i] : cheapestNode; minCost = Mathf.Min(minCost, solutionNodes[i].costSoFar); } GOAPNode curNode = cheapestNode; List <GOAPAction> path = new List <GOAPAction>(); while (curNode != null) { if (curNode.action != null) { path.Insert(0, curNode.action); } curNode = curNode.parent; } Queue <GOAPAction> plan = new Queue <GOAPAction>(); foreach (GOAPAction a in path) { plan.Enqueue(a); } return(plan); }
public void ShouldHaveSameTokensAsClone() { foreach (WorldStateToken token in tokens) { ws.SetToken(token); } generic_astar.Action action = new generic_astar.Action("test_action", new List <WorldStateToken>() { }, new List <WorldStateToken>() { }, 10); GOAPNode node = new GOAPNode(ws, action); GOAPNode clone = (GOAPNode)node.Clone(); foreach (WorldStateToken token in tokens) { Assert.AreEqual(token.Value, clone.WorldState.GetValue(token.Name)); } }
/// <summary> 构建树并返回所有计划 </summary> /// <param name="_parent">父节点,不可为空</param> /// <param name="_usableActions">所有可行行为</param> /// <param name="_goal">目标计划</param> /// <param name="_leaves">已找到的所有计划</param> /// <returns>是否找到计划</returns> private bool BuildGraph(GOAPNode _parent, List <GOAPAction> _usableActions, GOAPGoal _goal, int _depth, int _maxDepth, List <GOAPNode> _leaves) { if (_maxDepth >= 1 && _depth >= _maxDepth) { return(false); } foreach (GOAPAction action in _usableActions) { // 不允许出现两个连续的相同行为 if (_parent == null || action == _parent.action || !action.IsProceduralPrecondition(_parent.state)) { continue; } if (InState(_parent.state, action.Preconditions)) { // 造成效果影响当前状态 Dictionary <string, bool> currentState = PopulateState(_parent.state, action.Effects); // 生成动作完成的节点链,成本累加 GOAPNode node = NodePool.Spawn(_parent, _parent.runningCost + action.Cost, currentState, action); // 如果当前状态能够达成目标 if (currentState.TryGetValue(_goal.Key, out bool value) && value.Equals(_goal.Value)) { _leaves.Add(node); } else { BuildGraph(node, _usableActions, _goal, ++_depth, _maxDepth, _leaves); } } } return(_leaves.Count > 0); }
/// <summary> 定制最优计划 </summary> /// <param name="_agent">代理</param> /// <param name="_availableActions">所有可用行为</param> /// <param name="_currentStates">当前状态</param> /// <param name="_goal">目标状态,想要达到的状态</param> public void Plan(GOAPAction[] _availableActions, Dictionary <string, bool> _currentStates, GOAPGoal _goal, int _maxDepth, ref Queue <GOAPAction> _plan) { if (_currentStates.TryGetValue(_goal.Key, out bool value) && value.Equals(_goal.Value)) { return; } NodePool.RecycleAll(); // 所有可用的行为 usableActions.Clear(); foreach (var action in _availableActions) { if (action.IsUsable()) { action.DynamicallyEvaluateCost(); usableActions.Add(action); } } // 根节点 root = NodePool.Spawn(null, 0, _currentStates, null); // 所有能达到目标的节点 leaves.Clear(); // 成本最低的计划节点 cheapestNode = null; // 成本最低计划 _plan.Clear(); // 如果通过构建节点树找到了能够达成目标的计划 if (BuildGraph(root, usableActions, _goal, 0, _maxDepth, leaves)) { Stack <GOAPAction> goapActionStack = Stack_Pool.Spawn(); foreach (GOAPNode leaf in leaves) { if (cheapestNode == null) { cheapestNode = leaf; } else if (cheapestNode.runningCost > leaf.runningCost) { cheapestNode = leaf; } } // 向上遍历并添加行为到栈中,直至根节点,因为从后向前遍历 while (cheapestNode != null) { goapActionStack.Push(cheapestNode.action); if (cheapestNode.parent.action != null) { cheapestNode = cheapestNode.parent; } else { break; } } //goapActions = new Queue<Action>(); // 再将栈压入到队列中 while (goapActionStack.Count > 0) { _plan.Enqueue(goapActionStack.Pop()); } Stack_Pool.Recycle(goapActionStack); } // 用完回收所有对象 DictionaryObjPool.RecycleAll(); }
public void TestGOAPConstructor() { GOAPNode state = }