行为树简介

与有限状态机不同,行为树是一个分层节点树, 它控制着决策的流程,以及 "任务"(或 "Action" )的执行。

树的叶节点是实际的指令,即我们的协同组件与系统其余部分交互的地方。

例如,在面向服务的体系结构中,叶节点将包含与执行操作的 "服务器" 通信的 "客户端" 代码。

在下面的例子中,我们可以看到在一个 Sequence 中执行两个 Action,DetectObjectGraspObject

树的其它节点,不是叶节点,控制 "执行流程"。

为了更好地理解这个控制流是如何发生的,请设想一个名为 "tick" 的信号。它在树的根部执行,并通过分支传播,直到到达一个或多个叶子节点。

注意

单词 tick 经常被用作动词(勾选/被勾选),它的意思是 "调用一个 TreeNode 的回调 tick() "。

当一个 TreeNode 被勾选,它返回的 NodeStatus 应为下述之一:

  • SUCCESS
  • FAILURE
  • RUNNING

顾名思义,前两个告诉父节点它们的操作是成功还是失败。

异步节点的执行未完成并且需要更多时间来返回有效结果时,将返回 RUNNING 。

异步节点可以停止

节点的结果将回传给它的父节点,父节点将决定下一步应勾选哪个子节点,或者可以将结果返回给自己的父节点。

节点类型

ControlNode 是可以有1到N个子节点的节点。一旦收到 tick,该 tick 可以传播到一个或多个子节点。

DecoratorNode 与 ControlNode 相似,但只能有一个子节点。

ActionNode 是叶节点,没有任何子节点。用户应实现自己的 ActionNode 来执行实际任务。

ConditionNode 与 ActionNode 等价,但它们始终是原子和同步的,即它们不得返回 RUNNING。它们不应改变系统的状态。

示例

为了更好地了解行为树的工作原理,让我们关注一些实例。为了简单起见,我们将不考虑 Action 返回 RUNNING 时发生的情况。

我们将假定每个 Action 都是原子且同步执行的。

第一个 ControlNode:Sequence

让我们用最基本和最常用的 ControlNode:SequenceNode,来说明行为树是如何工作的。

ControlNode 的子节点始终是有序的;在图形表示中,执行顺序是从左到右

简而言之:

  • 如果一个子节点返回 SUCCESS,则勾选下一个。
  • 如果一个子节点返回 FAILURE,则不再勾选子节点,并且该 Sequence 返回 FAILURE。
  • 如果所有子节点都返回 SUCCESS,则该 Sequence 也返回 SUCCESS。

您发现错误了吗?

如果 Action GrabBeer 失败,则由于跳过了最后一个 Action CloseFridge,冰箱的门将保持打开状态。

Decorators

根据 DecoratorNode 的类型,该节点的目标可以是:

  • 转换从子节点那里收到的结果,
  • 停止子节点的执行,
  • 根据 Decorator 的类型重复勾选子节点。

您可以创建自己的 Decorator 来扩展语法。

节点 Inverter 是一个 Decorator,它对子节点返回的结果进行取反。因此,后面跟有称为 DoorOpen 的节点的 Inverter 等效于

"Is the door closed?".

如果子节点 OpenDoor 返回 FAILURE,节点 Retry 将对该子节点重复勾选N次(本例中为3次)。

显然,右侧的分支表示:

If the door is closed, then try to open it.
Try up to 3 times, otherwise give up and return FAILURE.

但...

您发现错误了吗?

如果 DoorOpen 返回 FAILURE,则我们会执行期望的行为。但是,如果返回 SUCCESS,则左分支失败,整个 Sequence 被中断。

稍后我们将看到如何改进此树。

第二个 ControlNode:Fallback

FallbackNode(也称为 "Selectors" ),顾名思义,是可以表达 Fallback 策略的节点,即,如果一个子节点返回 FAILURE,下一步该怎么做。

它按顺序勾选子节点,并且:

  • 如果一个子节点返回 FAILURE,则勾选下一个。
  • 如果一个子节点返回 SUCCESS,则不会再勾选任何子节点,并且该 Fallback 返回 SUCCESS。
  • 如果所有子节点都返回 FAILURE,那么该 Fallback 也返回 FAILURE。

在下一个示例中,您将看到如何组合 Sequence 和 Fallback:

门开着吗?

如果没有,请尝试打开门。

否则,如果您有钥匙,请开锁并打开门。

否则,砸门。

如果这些操作中的任何一个成功,请进入房间。

重新回到 "Fetch me a beer"

现在,我们可以改进 "Fetch Me a Beer" 示例,如果啤酒不在冰箱内,则该示例将门保持打开状态。

我们使用 "绿色" 表示返回 SUCCESS 的节点,使用 "红色" 表示返回 FAILURE 的节点。黑色节点表示尚未执行。

让我们创建一个替代树,即使 GrabBeer 返回 FAILURE 时,它也会关闭门。

这两棵树最终都会关闭冰箱的门,但是:

  • 不管我们是否真的拿过啤酒,左侧的树都将始终返回 SUCCESS。
  • 如果有啤酒,则右侧的树将返回 SUCCESS,否则将返回 FAILURE。

如果 GrabBeer 返回 SUCCESS,则一切正常。

原文地址:https://www.cnblogs.com/xGonZh10n/p/12868391.html