/// <summary> /// Deep copies the tree. /// Make sure that the original behaviour tree has its pre-orders calculated. /// </summary> /// <param name="originalBT"></param> /// <returns></returns> public static BehaviourTree Clone(BehaviourTree originalBT) { var cloneBt = Instantiate(originalBT); if (originalBT._blackboard) { cloneBt._blackboard = Instantiate(originalBT._blackboard); } cloneBt.allNodes.Clear(); Action <BehaviourNode> copier = (originalNode) => { var nodeCopy = Instantiate(originalNode); // Linke the root copy. if (originalBT.Root == originalNode) { cloneBt.Root = nodeCopy; } // Nodes will be added in pre-order. nodeCopy.ClearTree(); nodeCopy.Tree = cloneBt; }; // Traversing in tree order will make sure that the runtime tree has its nodes properly sorted // in pre-order and will also make sure that dangling nodes are left out (unconnected nodes from the editor). TreeIterator <BehaviourNode> .Traverse(originalBT.Root, copier); // At this point the clone BT has its children in pre order order // and the original BT has pre-order indices calculated for each node. // // RELINK children and parent associations of the cloned nodes. // The clone node count is <= original node count because the editor may have dangling nodes. int maxCloneNodeCount = cloneBt.allNodes.Count; for (int i = 0; i < maxCloneNodeCount; ++i) { BehaviourNode originalNode = originalBT.allNodes[i]; BehaviourNode originalParent = originalNode.Parent; if (originalParent) { BehaviourNode copyNode = GetInstanceVersion(cloneBt, originalNode); BehaviourNode copyParent = GetInstanceVersion(cloneBt, originalParent); copyParent.ForceSetChild(copyNode); } } for (int i = 0; i < maxCloneNodeCount; ++i) { cloneBt.allNodes[i].OnCopy(); } IncludeTreeReferences(cloneBt); return(cloneBt); }
/// <summary> /// Computes the pre and post orders of all nodes. /// </summary> public void CalculateTreeOrders() { ResetOrderIndices(); int orderCounter = 0; Action <BehaviourNode> preOrder = (node) => { node.preOrderIndex = orderCounter++; }; TreeIterator <BehaviourNode> .Traverse(_root, preOrder); orderCounter = 0; Action <BehaviourNode> postOrder = (node) => { node.postOrderIndex = orderCounter++; }; TreeIterator <BehaviourNode> .Traverse(_root, postOrder, Traversal.PostOrder); Action <BehaviourNode, TreeIterator <BehaviourNode> > levelOrder = (node, itr) => { node.levelOrder = itr.CurrentLevel; // This will end up with the highest level. Height = itr.CurrentLevel; }; TreeIterator <BehaviourNode> .Traverse(_root, levelOrder, Traversal.LevelOrder); }
/// <summary> /// A helper method to traverse all nodes and execute an action per node. /// This method also passes the iterator doing the traversal. /// </summary> /// <param name="root">The traversal start.</param> /// <param name="onNext">The action to execute per node.</param> /// <param name="traversal">The type of DFS traversal.</param> public static void Traverse(T root, Action <T, TreeIterator <T> > onNext, Traversal traversal = Traversal.PreOrder) { var itr = new TreeIterator <T>(root, traversal); while (itr.HasNext()) { var node = itr.Next(); onNext(node, itr); } }
/// <summary> /// A helper method to traverse all nodes and accumulate a value over the traversal. /// </summary> /// <typeparam name="TAccum"></typeparam> /// <param name="root"></param> /// <param name="accumulator">The function used to accumulate the value</param> /// <param name="initial">The starting value for the accumulation</param> /// <param name="traversal"></param> /// <returns></returns> public static TAccum Traverse <TAccum>(T root, Func <TAccum, T, TAccum> accumulator, TAccum initial, Traversal traversal = Traversal.PreOrder) { var itr = new TreeIterator <T>(root, traversal); while (itr.HasNext()) { var node = itr.Next(); initial = accumulator(initial, node); } return(initial); }
/// <summary> /// A pre-order traversal with the option to skip some nodes. /// </summary> /// <param name="root"></param> /// <param name="onNext"></param> /// <param name="skipFilter"></param> public static void Traverse(T root, Action <T> onNext, Func <T, bool> skipFilter) { if (skipFilter(root)) { return; } var itr = new TreeIterator <T>(root); itr._skipFilter = skipFilter; while (itr.HasNext()) { var node = itr.Next(); onNext(node); } }
/// <summary> /// A helper method to traverse all nodes and execute an action per node. /// </summary> /// <param name="root">The travseral start.</param> /// <param name="onNext">The action to execute per node.</param> /// <param name="traversal">The type of DFS traversal.</param> public static void Traverse( T root, Action <T> onNext, Traversal traversal = Traversal.PreOrder, TraversalSkip skip = TraversalSkip.None) { var itr = new TreeIterator <T>(root, traversal); if (skip == TraversalSkip.Root) { itr.Next(); } while (itr.HasNext()) { var node = itr.Next(); onNext(node); } }
private void SyncIterators() { SyncParallelIterators(); _root._iterator = _mainIterator; BehaviourIterator itr = _mainIterator; var parallelRoots = new Stack <BehaviourNode>(); // This function handles assigning the iterator and skipping nodes. // The parallel root uses the same iterator as its parent, but the children // of the parallel node use their own iterator. Func <BehaviourNode, bool> skipAndAssign = (node) => { node._iterator = itr; bool bIsParallel = node as Parallel != null; if (bIsParallel) { parallelRoots.Push(node); } return(bIsParallel); }; Action <BehaviourNode> nothing = (node) => { }; // Assign the main iterator to nodes not under any parallel nodes. TreeIterator <BehaviourNode> .Traverse(_root, nothing, skipAndAssign); while (parallelRoots.Count != 0) { BehaviourNode parallel = parallelRoots.Pop(); // Do passes for each child, using the sub iterator associated with that child. for (int i = 0; i < parallel.ChildCount(); ++i) { itr = (parallel as Parallel).GetIterator(i); TreeIterator <BehaviourNode> .Traverse(parallel.GetChildAt(i), nothing, skipAndAssign); } } }