根据我对行为树的理解,每个行为应该是面向目标的短期动作,可以在几次迭代中完成。
例如,以下是行为树的图像:
现在假设驶向敌人行为在树中需要多次迭代。因此,每次通过时都会调用驶向敌人,因为它现在处于运行状态。
问题是我希望在附近有敌人时调用躲避敌人。考虑到驶向敌人总是被调用,我从未有机会调用躲避敌人(可能应该称为避开敌人)。
- 我应该在每次通过时无论当前运行什么动作都遍历树吗?
- 我的方法正确吗?
- 处理这种行为的正确方法是什么?
回答:
我认为每次都回到顶部进行遍历应该是你最后的选择,如果下面的方法对你不起作用的话:
正如Alex Champandard在他的网站aigamedev.com上所建议的,基本的想法是,当你在执行“驶向敌人”行为时,你应该包含某种方式来运行一些额外的检查,以确保该行为应该继续进行。
Alex的方法是使用并行复合节点:一种同时运行所有子节点的行为树节点类型。
它看起来会是这样:
- 主选择器:
- 躲避敌人
- 定位敌人
- 朝相反方向行驶
- 并行
- 敌人是否靠近?
- 追逐敌人
- 寻找通往敌人的路径
- 驶向敌人
- 开火
- 追逐旗帜
- 定位旗帜
- 寻找路径
- 驶向旗帜
- 躲避敌人
并行节点将持续反复评估“敌人是否靠近?”节点(以合理的速度),即使执行已经深入到“追逐敌人”子树中。一旦“敌人是否靠近?”返回失败,并行节点将立即返回失败并跳过完成“追逐敌人”行为。因此,树的下一次评估将到达“躲避敌人”行为。
然后,“敌人是否靠近?”条件就像是一种断言检查或提前退出检查。本质上,它类似于一个事件驱动的功能,即使树尚未完成其迭代,也可以对事件做出响应。
然而,我设计的系统不使用并行行为(我使用的第三方游戏引擎无法正确地多线程处理)。相反,我有一个复合节点,它几乎做同样的事情,只是它在每个子节点遍历之间评估检查。就像一种交错的,从正常执行跳转到评估检查的来回跳跃。只有当检查失败时,我们才会跳回到顶部。