CryEngine里的行为选择树(Behavior Selection Tree)【转载】
前些日子,经人推荐,看了一些CryEngine里AI部分的介绍,当然,作为一个大型商业引擎,AI部分涵盖了很多内容,特别的,我注意到里面关于行为树的部分,从CryEngine 3.3开始,行为树被舍弃了,取而代之的是称为“行为选择树”的模块,我并没有找到关于为何要做出这样的选择的官方说明,因此,我就仔细阅读了关于行为选择树的一些文档,记录在这里,因为我并没有用过CryEngine以及它所提供的相关工具,以下所有的心得都源自对于官方文档的阅读,如有不对,欢迎指正和讨论。
行为选择树(Behavior Selection Tree),顾名思义,它的重点在于为“行为”和“选择”
- 行为:AI在每一个时刻,都必须处在某一个行为中
- 选择:AI在每一个时候,都会根据外部的条件,选择某一个行为作为当前的行为状态
这两点并不是很难理解,换句话说,就是每一个AI智能体都永远处在它所应该在的行为状态中(当然,这里的“应该”指人为预设的行为选择逻辑)
在行为选择树中有几个相关的概念,或者说术语
- 选择变量(Selection Variable):用来做选择逻辑的变量值,其实说白了,就可以认为是一个布尔值,要么是真(True),要么是假(False)
- 信号变量(Signal Variable):用来改变“选择变量”的事件,“信号”是有外部的AI系统或行为选择树本身发出的,在行为选择树中,信号变量是和选择变量绑定的,要改变选择变量,官方建议是通过发送信号来实现(不建议直接修改),比如有一个信号变量是OnEnemyDead,一个选择变量是IsEnemyDead,那么当行为选择树收到这个信号时,就会把IsEnemyDead设成True,这样就影响了行为选择树的选择逻辑。
- 叶节点映射(Leaf Transition):定义了名字和行为的关系,相当于给行为节点定义了一个别名。在行为选择树的定义中,节点是用别名来引用的,这样的好处就是,行为树的结构是可以复用的。
为了更好的说明上面复用的问题,我们可以举这样一个例子,比如有两种动物,一个是猫,一个是狗,同样是闲逛,猫有猫的方式CatWalk(猫步?),狗有狗的方式DogWalk,同样是吃饭,猫是CatEating,狗是DogEating,当饿的时候,会从闲逛行为切换到吃饭行为,吃饱了,就会再次切换回闲逛,所以对这两种动物来说,它们的行为选择树结构和逻辑上是一样的,不一样的只是他们的具体行为的执行方式,所以他们的行为选择树是可以复用的,叶节点映射就可以很好的处理这种情况,如下面的定义文件示例
--猫的叶节点映射
<
LeafTranslations
>
<
Map
node
=
"Walk"
target
=
"CatWalk"
/> --定义此别名所对应的具体行为
<
Map
node
=
"Eat"
target
=
"CatEating"
/>
</
LeafTranslations
>
--狗的叶节点映射
<
LeafTranslations
>
<
Map
node
=
"Walk"
target
=
"DogWalk"
/>
<
Map
node
=
"Eat"
target
=
"DogEating"
/>
</
LeafTranslations
>
--行为选择树定义,使用的时候别名,而不是具体行为的名字
<
Priority
name
=
"Root"
>
<
Leaf
name
=
"Eat"
condition
=
"IAmHungry"
/> --选择条件是饿了
<
Leaf
name
=
"Walk"
/>
</
Priority
>
基本上,以上这些就是行为选择树的全部概念了,和行为树比起来,我觉得有两个比较明显的不同:
- 对于“前提”(Precondition)的处理:在行为树的定义中,“前提”是可以带逻辑的,或是简单的逻辑代码,也或是复杂的逻辑代码,而在行为选择树中,它的前提被定义成了一个和“信号”所绑定的布尔变量,也就是说在它的前提中,不包含对于逻辑的计算,所有的这些计算都是在外部的其他AI模块(比如,感知系统,团队系统等等)中。所以行为选择树的“前提”可以看成是对一般的行为树前提的一个严格限定。
- 叶节点映射:行为树的定义中,并没有别名系统,即使行为树的结构是一样的,但不同的智能体上也会绑定各自的行为树。行为选择树很好的引入了别名系统,这样就可以使行为树得到了复用,可以说,这一点是对行为树的一个改进。
CryEngine中提供了一个编辑器来生成行为选择树,从文档的介绍来看,可以很好的编辑,调试和管理行为选择树。我想之所以行为选择树有这样的设计,和编辑器,以及整个AI系统的融合有很大的关系。编辑器的要求就是直观,对于前提的简单处理可以很好的保证这一点,比如,我可以仅仅改变一个选择变量就改变其行为选择,对于调试来说,也是极为便利的,设想一下如果前提是带有逻辑运算的,那在编辑器中,那就需要再写一个前提脚本来配置前提,会相对复杂得多。
另外,在实际开发中,会发现对于树(或者树的某个分支)的复用是十分必要的,就像我们不喜欢代码的冗余一样,对于行为树的冗余,有时也是不能接受的,所以不管从树的设计上来说,还是编辑器来说都要提供复用的架构设计,行为选择树就很好的做到了这一点,特别要指出的是,简单的前提设计在复用上有提供了一个很好的帮助,因为它仅仅是一个变量,所以在前提部分我们就不需要特别关注复用的问题了。如果是带复杂逻辑的前提,那势必我们还需要关心前提的复用问题。简单就是美啊!
总结下,行为选择树可以看成是对行为树的部分功能简化,和拓展,为编辑器的设计,为调试带来了很大的帮助,当然,由于它把前提的运算移到了外部,所以就更多的需要外围其他AI系统的支援了。有兴趣的朋友,不妨到CryEngine的主页了解试用一下这个引擎和它的行为选择树。
参考资料:
http://freesdk.crydev.net/display/SDKDOC2/Behavior+Selection+Tree+Editor
http://freesdk.crydev.net/display/SDKDOC5/Behavior+Selection+Trees
—————————————————————————————
作者:Finney
Blog:AI分享站(http://www.aisharing.com/)
Email:finneytang@gmail.com
本文欢迎转载和引用,请保留本说明并注明出处
—————————————————————————————