Esempio n. 1
0
        /// <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>
        /// Ticks the iterator.
        /// </summary>
        public void Update()
        {
            CallOnEnterOnQueuedNodes();
            TickBranch();

            int           index = _traversal.Peek();
            BehaviourNode node  = _tree.allNodes[index];

            LastStatusReturned = node.Run();

#if UNITY_EDITOR
            node.SetStatusEditor(LastStatusReturned);
#endif

            if (LastStatusReturned != BehaviourNode.Status.Running)
            {
                PopNode();
                CallOnChildExit(node);
            }

            if (_traversal.Count == 0)
            {
                OnDone();
            }
        }
        /// <summary>
        /// Tells the iterator to abort the current running subtree and jump to the aborter.
        /// </summary>
        /// <param name="aborter"></param>
        public void OnAbort(ConditionalAbort aborter)
        {
            BehaviourNode parent           = aborter.Parent;
            int           terminatingIndex = BehaviourNode.kInvalidOrder;

            if (parent)
            {
                terminatingIndex = parent.preOrderIndex;
            }

            // If an abort node is the root, then we need to empty the entire traversal.
            // We can achieve this by setting the terminating index to the invalid index, which is an invalid index
            // and will empty the traversal.
            while (_traversal.Count != 0 && _traversal.Peek() != terminatingIndex)
            {
                StepBackAbort();
            }

            // Only composite nodes need to worry about which of their subtrees fired an abort.
            if (parent.MaxChildCount() > 1)
            {
                parent.OnAbort(aborter);
            }

            // Any requested traversals are cancelled on abort.
            _requestedTraversals.Clear();

            Traverse(aborter);
        }
Esempio n. 4
0
        /// <summary>
        /// Ticks the iterator.
        /// </summary>
        public void Update()
        {
            CallOnEnterOnQueuedNodes();
            int           index = traversal.Peek();
            BehaviourNode node  = tree.Nodes[index];

            BehaviourNode.Status s = node.Run();

            LastExecutedStatus = s;

#if UNITY_EDITOR
            node.StatusEditorResult = (BehaviourNode.StatusEditor)s;
#endif

            if (s != BehaviourNode.Status.Running)
            {
                PopNode();
                OnChildExit(node, s);
            }

            if (traversal.Count == 0)
            {
                OnDone();
            }
        }
Esempio n. 5
0
        /// <summary>
        /// Test if the aborter may abort the node.
        /// Make sure that the node orders are pre-computed before calling this function.
        /// This method is mainly used by the editor.
        /// </summary>
        /// <param name="aborter">The node to perform the abort.</param>
        /// <param name="node">The node that gets aborted.</param>
        /// <returns></returns>
        public static bool IsAbortable(ConditionalAbort aborter, BehaviourNode node)
        {
            // This makes sure that dangling nodes do not show that they can abort nodes under main tree.
            if (aborter.preOrderIndex == kInvalidOrder)
            {
                return(false);
            }

            // Parallel subtrees cannot abort each other.
            if (aborter.Parent && aborter.Parent is Parallel)
            {
                return(false);
            }

            switch (aborter.abortType)
            {
            case AbortType.LowerPriority:
                return
                    (!BehaviourTree.IsUnderSubtree(aborter, node) &&
                     BehaviourTree.IsUnderSubtree(aborter.Parent, node) &&
                     aborter.Priority() > GetSubtree(aborter.Parent, node).Priority());

            // Self aborts always interrupt, regardless of the condition.
            case AbortType.Self:
                return(BehaviourTree.IsUnderSubtree(aborter, node));

            case AbortType.Both:
                return
                    (BehaviourTree.IsUnderSubtree(aborter, node) ||
                     (BehaviourTree.IsUnderSubtree(aborter.Parent, node) &&
                      aborter.Priority() > GetSubtree(aborter.Parent, node).Priority()));
            }

            return(false);
        }
Esempio n. 6
0
        /// <summary>
        /// Adds a child if it is parentless.
        /// </summary>
        /// <param name="child"></param>
        public sealed override void AddChild(BehaviourNode child)
        {
            if (child == null)
            {
                Debug.LogWarning("Child is null");
                return;
            }

            if (child == this)
            {
                Debug.LogWarning("A child cannot be its own child.");
                return;
            }

            if (child.Parent == null)
            {
                child.Parent      = this;
                child._indexOrder = _children.Count;
                _children.Add(child);
            }

            else
            {
                Debug.LogWarning("Composite node attempted to parent a child that already has a set parent.");
            }
        }
 private void CallOnChildEnter(BehaviourNode node)
 {
     if (node.Parent)
     {
         node.Parent.OnChildEnter(node._indexOrder);
     }
 }
Esempio n. 8
0
        /// <summary>
        /// Removes the child from its children, if it is the parent of the child.
        /// </summary>
        /// <param name="child"></param>
        public sealed override void RemoveChild(BehaviourNode child)
        {
            if (child == null)
            {
                return;
            }

            // Assure that this child was actually parented to this composite node.
            if (child.Parent == this)
            {
                // Forget about this child.
                bool bRemoved = _children.Remove(child);

                // If removed then we unparent the child.
                if (bRemoved)
                {
                    child._indexOrder = 0;
                    child._parent     = null;

                    UpdateIndexOrders();
                }

                // BIG ERROR. This should not happen.
                // The theory is that the only way for a child to have its parent set if it was null
                // which gets handled internally by the standard node types: Composite and Decorator.
                else
                {
                    const string msg1 = "Error on CompositeNode.Remove(child). ";
                    const string msg2 = "A child was parented to a composite node but was not found in the children list. ";
                    const string msg3 = "This should not have happend.";

                    Debug.LogError(String.Concat(msg1, msg2, msg3));
                }
            }
        }
Esempio n. 9
0
        public void Interrupt(BehaviourNode subroot, bool bFullInterrupt = false)
        {
            // Interrupt this subtree.
            subroot.Iterator.StepBackInterrupt(subroot, bFullInterrupt);

            // Look for parallel nodes under the subroot.
            // Since the parallel count is usually small, we
            // can just do a linear iteration to interrupt multiple
            // parallel nodes.
            for (int pIndex = 0; pIndex < _parallelNodeCount; ++pIndex)
            {
                Parallel p = _parallelNodes[pIndex];

                if (IsUnderSubtree(subroot, p))
                {
                    for (int itrIndex = 0; itrIndex < p.ChildCount(); ++itrIndex)
                    {
                        BehaviourIterator itr = p.GetIterator(itrIndex);

                        // Only interrupt running iterators.
                        if (itr.IsRunning)
                        {
                            // Get the child of the parallel node, and interrupt the child subtree.
                            int           childIndex = itr.FirstInTraversal;
                            BehaviourNode firstNode  = allNodes[childIndex];

                            itr.StepBackInterrupt(firstNode.Parent, bFullInterrupt);
                        }
                    }
                }
            }
        }
Esempio n. 10
0
 private void OnChildExit(BehaviourNode node, BehaviourNode.Status s)
 {
     if (node.Parent)
     {
         node.Parent.OnChildExit(node.indexOrder, s);
         LastChildExitStatus = s;
     }
 }
Esempio n. 11
0
 private void OnChildEnter(BehaviourNode node)
 {
     if (node.Parent)
     {
         LastChildExitStatus = null;
         node.Parent.OnChildEnter(node.indexOrder);
     }
 }
        /// <summary>
        /// Gets the subtree that is running under a parent.
        /// This does not work directly under parallel nodes since they use their own iterator.
        /// </summary>
        /// <param name="parent"></param>
        /// <returns></returns>
        public BehaviourNode GetRunningSubtree(BehaviourNode parent)
        {
            int parentIndexInTraversal  = GetIndexInTraversal(parent);
            int subtreeIndexInTraversal = parentIndexInTraversal + 1;

            int subtreePreOrder = _traversal.GetValue(subtreeIndexInTraversal);

            return(_tree.allNodes[subtreePreOrder]);
        }
Esempio n. 13
0
 /// <summary>
 /// <para>Set the child for the decorator node.</para>
 /// <para>
 /// This should be called <b>once</b> when the tree is being built,
 /// before Tree Start() and never during Tree Update()
 /// </para>
 /// </summary>
 public void SetChild(BehaviourNode node)
 {
     child = node;
     if (child != null)
     {
         child.Parent     = this;
         child.indexOrder = 0;
     }
 }
Esempio n. 14
0
        private static BehaviourNode GetSubtree(BehaviourNode parent, BehaviourNode grandchild)
        {
            BehaviourNode sub = grandchild;

            while (sub.Parent != parent)
            {
                sub = sub.Parent;
            }
            return(sub);
        }
Esempio n. 15
0
 private void CallOnEnterOnQueuedNodes()
 {
     // Make sure to call on enter on any queued new traversals.
     while (requestedTraversals.Count != 0)
     {
         int           i    = requestedTraversals.Dequeue();
         BehaviourNode node = tree.Nodes[i];
         node.OnEnter();
         OnChildEnter(node);
     }
 }
        /// <summary>
        /// Tests if node is under the root tree.
        /// </summary>
        /// <param name="root"></param>
        /// <param name="node"></param>
        /// <returns></returns>
        public static bool IsUnderSubtree(BehaviourNode root, BehaviourNode node)
        {
            // Assume that this is the root of the tree root.
            // This would happen when checking IsUnderSubtree(node.parent, other)
            if (root == null)
            {
                return(true);
            }

            return(root.PostOrderIndex > node.PostOrderIndex && root.PreOrderIndex < node.PreOrderIndex);
        }
Esempio n. 17
0
        /// <summary>
        /// DANGER!
        /// Directly sets the child (at its relative index.
        /// This is used to help clone nodes.
        /// </summary>
        /// <param name="child"></param>
        public sealed override void ForceSetChild(BehaviourNode child)
        {
            child.ClearParent();
            child.Parent = this;

            // Do not bother with unsetting the original child's parent.
            // The original child is already properly setup in its tree.
            // This is used when trying to build a tree copy, so we can
            // simply set a new child at that index.
            _children[child.ChildOrder] = child;
        }
Esempio n. 18
0
        /// <summary>
        /// Requests the iterator to traverse a new node.
        /// </summary>
        /// <param name="next"></param>
        public void Traverse(BehaviourNode next)
        {
            int index = next.preOrderIndex;

            traversal.Push(index);
            requestedTraversals.Enqueue(index);

#if UNITY_EDITOR
            next.StatusEditorResult = BehaviourNode.StatusEditor.Running;
#endif
        }
Esempio n. 19
0
        private void stepBackAbort()
        {
            int index = _traversal.Pop();

            BehaviourNode node = _tree.allNodes[index];

            node.OnExit();

#if UNITY_EDITOR
            node.SetStatusEditor(BehaviourNode.StatusEditor.Aborted);
#endif
        }
Esempio n. 20
0
        // Editor only helper method.
        // Clears all nodes, children, and sets the tree reference to null.
        public void ClearStructure()
        {
            foreach (BehaviourNode node in allNodes)
            {
                node.ClearChildren();
                node.ClearTree();
            }

            allNodes.Clear();

            _root = null;
        }
Esempio n. 21
0
        private BehaviourNode PreOrderNext()
        {
            BehaviourNode current = traversal.Pop();

            for (int i = current.ChildCount() - 1; i >= 0; --i)
            {
                BehaviourNode child = current.GetChildAt(i);
                traversal.Push(child);
            }

            return(current);
        }
Esempio n. 22
0
        /// <summary>
        /// DANGER!
        /// Directly sets the child.
        /// This is used to help clone nodes.
        /// </summary>
        /// <param name="child"></param>
        public sealed override void ForceSetChild(BehaviourNode child)
        {
            child.ClearParent();

            // Do not bother with unsetting the original child's parent.
            // The original child is already properly setup in its tree.
            // This is used when trying to build a tree copy, so we can
            // simply null the reference and set a new child.
            _child = null;

            AddChild(child);
        }
Esempio n. 23
0
        /// <summary>
        /// Sums the utility values of the traversed branch.
        /// </summary>
        /// <param name="root"></param>
        /// <param name="initial"></param>
        /// <returns></returns>
        public float SumUtility(BehaviourNode root, float initial = 0f)
        {
            traversal.Push(root);

            while (HasNext())
            {
                var node = Next();
                initial += node.UtilityValue();
            }

            traversal.Clear();
            return(initial);
        }
Esempio n. 24
0
        /// <summary>
        /// Gets the maximum maximum for the traversed branch.
        /// </summary>
        /// <param name="root"></param>
        /// <param name="initial"></param>
        /// <note>int.MinValue is used because that is lowest possible pre order priority value.</note>
        /// <returns></returns>
        public float MaxUtility(BehaviourNode root, float initial = int.MinValue)
        {
            traversal.Push(root);

            while (HasNext())
            {
                var node = Next();
                initial = Math.Max(initial, node.UtilityValue());
            }

            traversal.Clear();
            return(initial);
        }
        /// <summary>
        /// Requests the iterator to traverse a new node.
        /// </summary>
        /// <param name="next"></param>
        public void Traverse(BehaviourNode next)
        {
            int index = next.preOrderIndex;

            _traversal.Push(index);
            _requestedTraversals.Enqueue(index);

            LastStatusReturned = BehaviourNode.Status.Running;

#if UNITY_EDITOR
            next.SetStatusEditor(BehaviourNode.Status.Running);
#endif
        }
        private void ClearChildrenStructure(BehaviourNode node)
        {
            if (node.IsComposite())
            {
                var composite = node as Composite;
                composite.SetChildren(new BehaviourNode[] { });
            }

            else if (node.IsDecorator())
            {
                var decorator = node as Decorator;
                decorator.SetChild(null);
            }
        }
        private static void GetCompositeParent(
            BehaviourNode child,
            out BehaviourNode compositeParent,
            out int branchIndex)
        {
            compositeParent = child.Parent;
            branchIndex     = child.indexOrder;

            while (compositeParent && !compositeParent.IsComposite())
            {
                branchIndex     = compositeParent.indexOrder;
                compositeParent = compositeParent.Parent;
            }
        }
Esempio n. 28
0
        /// <summary>
        /// Removes the child, if it is the parent of the child.
        /// </summary>
        /// <param name="child"></param>
        public sealed override void RemoveChild(BehaviourNode child)
        {
            // Cannot be null and child must match.
            if (_child == null || _child != child)
            {
                return;
            }

            // Unparent the child.
            _child._parent = null;

            // This decorator forgets about its child.
            _child = null;
        }
        private void CallOnChildExit(BehaviourNode node)
        {
            // If this is not a root node, then notify the parent about the child finishing.
            if (_traversal.Count > 0)
            {
                node.Parent.OnChildExit(node._indexOrder, LastStatusReturned);
            }

            // If this was a subtree under a parallel node, then notify its parent.
            else if (node.Parent && _tree.IsParallelNode(node.Parent))
            {
                node.Parent.OnChildExit(node._indexOrder, LastStatusReturned);
            }
        }
Esempio n. 30
0
        private BehaviourNode PopNode()
        {
            int           index = traversal.Pop();
            BehaviourNode node  = tree.Nodes[index];

            if (node.IsComposite())
            {
                for (int i = 0; i < node.ChildCount(); i++)
                {
                    node.GetChildAt(i).OnCompositeParentExit();
                }
            }

            node.OnExit();
            return(node);
        }