/// <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); }
/// <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); }
/// <summary> /// Called when a composite node has a child that activates when it aborts. /// </summary> /// <param name="child"></param> protected internal override void OnAbort(ConditionalAbort child) { // The default behaviour is to set the current child index of the composite // node to this child's index. if (IsChild(child)) { _currentChildIndex = child._indexOrder; } else { Debug.LogError("The node is not parented to this composite node."); } }
// Note on multiple aborts: // If there are multiple satisfied aborts, then // the tree picks the highest order abort (left most). private void TickObservers() { for (int i = 0; i < _observerAborts.Count; ++i) { ConditionalAbort node = _observerAborts[i]; // The iterator must be running since aborts can only occur under // actively running subtrees. if (!node.Iterator.IsRunning) { continue; } // If the condition is true then apply an abort. if (node.IsAbortSatisfied()) { node.Iterator.OnAbort(node); } } }
// Does nothing since tasks do not have children. protected internal sealed override void OnAbort(ConditionalAbort aborter) { }
/// <summary> /// Called when a child fires an abort. /// </summary> /// <param name="aborter"></param> public virtual void OnAbort(ConditionalAbort aborter) { }
// Does nothing since tasks do not have children. public sealed override void OnAbort(ConditionalAbort aborter) { }
/// <summary> /// Called when a child fires an abort. /// </summary> /// <param name="aborter"></param> protected internal virtual void OnAbort(ConditionalAbort aborter) { }