// -------------------------- // Start is called before the first frame update void Start() { navMeshAgent = this.gameObject.GetComponent <NavMeshAgent>(); navMeshAgent.autoBraking = false; // disable auto braking for continuous movement this.monsterYellingText.gameObject.SetActive(false); // disable UI yelling text // generate an HTN tree for this monster rootNode = generateHTNtree(); // generate a World State HTN_WorldState ws = new HTN_WorldState(false, false, false, false, false); // set all false initially, let the update function to update WorldState this.worldState = ws; // create a HTN planner planner = new HTN_Planner(this, worldState); }
/// <summary> /// Function to generate a plan for a given root node of HTN tree /// </summary> /// <param name="rootNode"></param> public void planning(HTN_node rootNode) { HTN_WorldState state = this.currentWorldState.clone(); // make a copy of the current state ArrayList finalPlanList = new ArrayList(); Stack <HTN_node> tasksNodes = new Stack <HTN_node>(); // stack for store Method node for backtracking Stack <ArrayList> backTrackingMethods = new Stack <ArrayList>(); // each list in this stack is a list of methods // stack for store planList for backtracking Stack <ArrayList> backTrackingPlan = new Stack <ArrayList>(); Stack <HTN_WorldState> states = new Stack <HTN_WorldState>(); // store the copy of states for backtracking tasksNodes.Push(rootNode); // put the root node into the task stack // while the stack is not empty while (!(tasksNodes.Count == 0)) { HTN_node taskNode = tasksNodes.Pop(); // if the node is a compound node if (taskNode is HTN_CompoundNode) { ArrayList methods = ((HTN_CompoundNode)taskNode).findSatisfiedMethods(this.currentWorldState); //HTN_MethodNode method = ((HTN_CompoundNode)taskNode).findSatisfiedMethod(this.currentWorldState); HTN_MethodNode method = (HTN_MethodNode)methods[0]; methods.RemoveAt(0); if (method != null) { // store the plan and the next method node for backtracking when needed backTrackingPlan.Push(new ArrayList(finalPlanList)); // clone the current plan list backTrackingMethods.Push(methods); states.Push(state.clone()); // push the subtasks of this method into the list (push backward since we want the first subtask to be pop next) for (int i = method.getChildren().Count - 1; i >= 0; i--) { tasksNodes.Push((HTN_node)method.getChildren()[i]); } } else { // restore to the saved backtracking state state = states.Pop(); finalPlanList = backTrackingPlan.Pop(); tasksNodes.Clear(); // empty the tasksNode stack // pop a methods list ArrayList btMethods = backTrackingMethods.Pop(); while (btMethods.Count == 0) { btMethods = backTrackingMethods.Pop(); } // get the first method in that list HTN_MethodNode btMethodNode = (HTN_MethodNode)btMethods[0]; btMethods.RemoveAt(0); // delete that method from the list if (btMethods.Count > 0) { backTrackingMethods.Push(btMethods); // put the method list back } // push the subtasks of this method into the list (push backward since we want the first subtask to be pop next) for (int i = btMethodNode.getChildren().Count - 1; i >= 0; i--) { tasksNodes.Push((HTN_node)btMethodNode.getChildren()[i]); } } } else // primative node { // if the precondition is met if (((HTN_PrimitiveNode)taskNode).verifyPrecondition(state)) { // apply the effect of this task on the world state ((HTN_PrimitiveNode)taskNode).applyTask(state); finalPlanList.Add(taskNode); // add this taskNode to the plan list // if this primitive task is the last in the stack, our planning is finish if (tasksNodes.Count == 0) { break; } } else { // restore to the saved backtracking state state = states.Pop(); finalPlanList = backTrackingPlan.Pop(); tasksNodes.Clear(); // empty the tasksNode stack // pop a methods list ArrayList btMethods = backTrackingMethods.Pop(); while (btMethods.Count == 0) { btMethods = backTrackingMethods.Pop(); } // get the first method in that list HTN_MethodNode btMethodNode = (HTN_MethodNode)btMethods[0]; btMethods.RemoveAt(0); // delete that method from the list if (btMethods.Count > 0) { backTrackingMethods.Push(btMethods); // put the method list back } // push the subtasks of this method into the list (push backward since we want the first subtask to be pop next) for (int i = btMethodNode.getChildren().Count - 1; i >= 0; i--) { tasksNodes.Push((HTN_node)btMethodNode.getChildren()[i]); } } } } this.plan = finalPlanList; // set the current plan to the final plan list }
/// <summary> /// Function to add child node to this node /// </summary> /// <param name="childNode"></param> public void addChild(HTN_node childNode) { this.children.Add(childNode); }