/// <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); }
public static void IncludeTreeReferences(BehaviourTree mainTree) { var includes = mainTree.GetNodes <Include>(); // Nothing to include. if (includes.Count == 0) { return; } var includedTrees = new BehaviourTree[includes.Count]; for (int i = 0; i < includes.Count; ++i) { // Clone each individual tree independently. Include include = includes[i]; BehaviourTree subtree = Clone(include.tree); BehaviourNode includeParent = include.Parent; BehaviourNode subtreeRoot = subtree.Root; if (includeParent) { // The root node must now be the child of the parent of the include. subtreeRoot._indexOrder = include._indexOrder; includeParent.ForceSetChild(subtreeRoot); } else if (include.preOrderIndex == 0) { // If the include node is the root, then just make the subtree the root. mainTree.Root = subtreeRoot; } #if UNITY_EDITOR Vector2 deltaFromSubrootToInclude = include.bonsaiNodePosition - subtreeRoot.bonsaiNodePosition; #endif // The nodes of the included tree, must now reference the main tree. foreach (BehaviourNode b in subtree.AllNodes) { b.ClearTree(); b.Tree = mainTree; #if UNITY_EDITOR // Offset the sub tree nodes so they are placed under the include node. b.bonsaiNodePosition += deltaFromSubrootToInclude; #endif } } // After everything is included, we need to resort the tree nodes in pre order with the new included nodes. mainTree.SortNodes(); // Destory the cloned subtrees since we do not need them anymore. for (int i = 0; i < includedTrees.Length; ++i) { Destroy(includedTrees[i]); } // Destroy the includes for (int i = 0; i < includes.Count; ++i) { Destroy(includes[i]); } }