总起:

行为树的节点不总是从上至下从左至右顺序执行的,在复合节点上有一个Abort Type参数。

Unity 刷草控制密度_Behavior Designer

 

该参数可以决定复合节点下的条件节点状态发生变化时,是否能打断当前子节点(self)、优先级比自己低的节点的执行(Lower Priority)。

 

打断机制:

行为树中拥有许多容器变量:

  1. taskList,所有的Task节点;
  2. conditionReevaluate,条件节点的状态缓存;
  3. activeStack,当前运行中Task的堆栈,行为树在启动时会新建一个,在碰到每个并行分支时会新建一个。

 

行为树的每次执行时一次Tick,最终会执行到当前在执行Task的OnUpdate,但是在此之前会执行ReevaluateConditionalTasks方法将当前缓存的条件节点重新判断一遍。

 

具体的判断如下:

Unity 刷草控制密度_打断机制_02

 

从conditionReevaluate获取需要判断的条件节点后,执行一次OnUpdate,如果其返回值与存储的状态不同,则开始打断。

 

将需要打断的任务从activeStack中弹出,并将正在运行中任务的结果置为Failure。

Unity 刷草控制密度_Unity 刷草控制密度_03

 

最后从当前节点往上追溯,调用其所有节点的OnConditionalAbort,并更新条件节点NodeData中的InterruptTime——被打断的时间。

 

打断的条件:

上小结中介绍了打断的基本流程,其中打断类型有四种:None、Self、LowerPriority、Both。

 

行为树中条件状态缓存conditionReevaluate,在条件节点运行时会加入该容器,但是有两个条件:

  1. 该Task必须继承Conditional,也就是条件节点(其实Conditional和Action的运行方式基本等同,如果不需要打断的功能Action节点完全可以替代Conditional节点。所以打断功能应该就是Conditional节点和Action节点的本质区别);
  2. AbortType必须不是AbortType.None。

 

加入到缓存中时,如果不是LowerPriority则会记录compositeParentIndex父复合节点的索引,否则为-1。

 

这边就有些奇怪了,因为在执行打断流程前有个判断:

Unity 刷草控制密度_打断机制_04

 

也就是说LowerPriority类型初始值并不会打断。断点看一下:

Unity 刷草控制密度_Unity_05

 

只要Task运行过便会进行赋值,而打断时conditionReevaluate会重置。