任务打断机制


behavior-dog 在执行一个行为树时,会按照前序遍历的规则依次执行节点任务,并根据任务的执行结果决定是否继续执行行为树。当任务不能在一帧内完成时, behavior-dog 会将他的状态标记为 运行中 ,然后在接下来每帧执行时,跳过遍历的步骤,直接执行该任务,直到他的状态变成 完成 为止。

由于 behavior-dog 不会重新遍历整棵树,因此当一个 运行中 的任务所依赖的外部条件发生变化时, behavior-dog 并不能及时做出响应。在行为树中,这个条件可以是比该任务优先级高的任何其他任务,因为行为树总是先执行高优先级的任务,再执行低优先级的任务。也可以是某个数据,比如黑板上的某一个键值,当他被修改时,任务的执行逻辑也将做出相应改变,甚至终止执行。

因此行为树需要有一个任务打断机制来响应这些变化。

拦截任务

使用 拦截任务 ,可以达到打断任务的目的。

拦截任务可由事件被动触发,也可以搭配触发器一起使用。

比如下面这 2 个内置的拦截任务,

拦截任务 拦截任务分组 触发器 触发器分组 描述
Gate Intercepter CtrlGate Action/Trigger 开关任务。当他打开时,子任务可以执行,当他关闭时,子任务终止。
Interrupt Intercepter RequestInterrupt Action/Trigger 中断任务。收到指定事件或触发器的中断请求时,打断子任务。

条件中断

条件中断是 组合任务 所特有的。

支持以下 4 种类型:

NONE SELF LOWER_PRIORITY BOTH
不打断 打断子任务 打断低优先级分支的任务 打断子任务和低优先级分支的任务
图片不见了?! 图片不见了?! 图片不见了?! 图片不见了?!

SELF

当有子任务被标记为 运行中 时,每帧评估该子任务 左边 的条件任务,再根据组合任务的执行规则决定是否打断 运行中 的子任务。

当前分支是运行分支时, SELF 打断才会生效。

举个赛车游戏的例子,在满足下列 2 个条件的情况下,赛车将 进入狂飙模式

  1. 氮气充足
  2. 玩家 按下 R 键

他的行为树在 预览模式下 看起来像是这样的,

图片不见了?!

此时,按照行为树的执行规则,在 SpeedBoost 任务不主动结束的情况下,赛车将一直处于狂飙模式。

但是我们希望执行的逻辑是,当上述 2 个条件中有一个不符合时,立即 退出狂飙模式

比如,氮气消耗完了 ,不管玩家按没按 R 键都应该退出狂飙模式。

➠ 这时打断机制就派上用场了。

Sequence 任务的 abortType 属性设置为 SELF

图片不见了?!

SELF 打断机制下, Sequence 任务会在执行 SpeedBoost 之前,先评估比他优先级高的其他条件子任务。当他们都返回成功时,才执行 SpeedBoost ,如果有一个返回失败,则立即打断 SpeedBoost

预览模式下可以看出,行为树不再只执行 SpeedBoost 任务了,而是每帧都重新评估 CmpNumIsKeyDown 任务。

图片不见了?!

SpeedBoost 任务被 CmpNum 任务打断时是这样的,

图片不见了?!

LOWER_PRIORITY

当低优先级的兄弟任务被标记为 运行中 时,每帧评估所有条件子任务,然后将结果报告给父任务,父任务再根据其规则决定是否打断 运行中 的子任务。

当前分支不是运行分支时, LOWER_PRIORITY 打断才会生效。

再举个例子,还是刚刚这个赛车游戏。

赛车在行驶过程中,如果:

  1. 氮气不足 或者
  2. 玩家 没按 R 键

赛车将 开始收集氮气

此时,行为树看起来像下面这样,

图片不见了?!

此时我们希望,当不满足上述 2 个条件时, 停止收集氮气

Sequence 任务的 abortType 属性设置为 LOWER_PRIORITY

图片不见了?!

LOWER_PRIORITY 打断机制下, Sequence 任务会评估自己的条件子任务,当他们都返回成功时, Sequence 也返回成功。而由 Selector 任务的规则得知,当 Sequence 这个子任务返回成功时, CollectBooster 任务是不会被执行的,因此打断 CollectBooster

预览模式下,

图片不见了?!

当玩家按下 R 键时,将会打断 CollectBooster 任务的执行,

图片不见了?!

BOTH

BOTH 表示同时支持 SELFLOWER_PRIORITY 打断机制。

上面例子中,当 Sequence 任务的 abortType 属性设置为 BOTH 时,将可以打断 CollectBoosterSpeedBoost2 个任务。

图片不见了?!

重新评估分支

重新评估分支也可以达到打断任务的目的。

他会每帧都 从头开始 执行分支下的所有子任务,而不是直接执行被 标记为运行 的子任务。

目前内置了以下 2 个重新评估分支任务,

任务 分组 描述
RevalSequence Composite 每帧从头开始执行子任务,当有一个子任务返回失败时,打断其他正在执行的子任务
RevalSelector Composite 每帧从头开始执行子任务,当有一个子任务返回成功时,打断其他正在执行的子任务

以上一节的赛车游戏为例。

我们可以将 Sequence 任务替换为 RevalSequence ,这样即使不设置 abortType 属性,行为树也会在执行 SpeedBooster 之前执行另外 2 个条件任务。

图片不见了?!

不过此时只有 SpeedBooster 任务能被打断,

图片不见了?!

而打断 CollectBooster 任务,需要

  • RevalSequenceabortType 属性设置为 LOWER_PRIORITY ,或者
  • Selector 也替换成 RevalSelector

比如,将 Selector 替换成 RevalSelector ,再看看预览结果,

图片不见了?!

results matching ""

    No results matching ""