现在战斗AI大部分都是行为树在做底层逻辑,而抛弃了以前的状态机。
好处很多:状态管理比较麻烦,尤其是状态很多很复杂的时候你想理清并不简单;反观行为树就不一样了,可以说是一个可编辑的行为过程,后期扩展维护也很方便。
Unity有行为树插件,但是只能用在客户端,你想做网络游戏就没有办法,除非你自己去解析。
所以这样我们自己编写一套行为树框架:为战斗策划提供配置支持。
下图是整个框架涉及到的东西。觉得疑惑的话没关系,毕竟都还没有开始说明。
上图是整个框架的结构图:
3. 配置:我们代码中写的节点类和事件类的列表,策划在编写AI脚本的时候需要;
4. 注册:根据策划编写的AI文件将事件实例和节点实例绑定在一起;
5. 触发:事件触发的时候就会执行绑定的节点(行为树根节点);
6. 运行时:给触发的节点提供运行环境;
所以我们涉及到两类东西:事件和节点。
策划提供的AI文件格式如下:
上图的文件可能是策划手动编写,也可能是通过工具生成,我们需要根据这份文件生成行为树的数据结构。
运行时
先从运行时说起。
行为树运行逻辑抽象成一句话:执行完当前节点后去执行下一个节点。
是不是很简单,我们看一些复杂点的:
上图是顺序模式、随机模式、循环模式的执行过程。
但是有一个问题就是节点2执行完成后可能继续执行节点3或者不在执行,节点得做出区分,我们就需要增对所有的节点编写大量的判断逻辑,节点与节点之间太过于耦合,显然不可取。我们看看下面的方式。
这样我们让节点与节点之间完全没有任何关系,所以得关系由模式去处理,这样在后期就能很方便的扩展了。
现在上面的结构接变成了:
根据上图这样看起来就够就统一了,这样就能将行为树的底层逻辑抽象出来:流程图如下
代码部分:
上图代码就是行为树运行时的全部逻辑了,你没有看错,就这么一点,是不是并不复杂。
运行时提供的功能有两个:执行当前节点和寻找下一个节点。
运行时有了,现在缺运行的具体事物,行为节点。
行为节点
为了简化节点的逻辑我们将节点分成两类:控制类节点和功能类节点。
控制类节点:控制子节点的流程;
功能类节点:不能有子节点,主要工作是执行自己;
NodeBase:所有节点的基类,提供公用的属性、方法和控制流程。
NormalNode:控制类节点:基础节点,顺序节点,循环节点,否定节点,判断节点,等待节点等等。
LevelNode:功能性节点:提供关卡相关的节点,UI显示节点,场景控制相关节点,战斗控制相关节点等等。
SkillNode:功能性节点:技能相关节点,释放技能节点,杀死目标节点,选择目标节点,预警节点等等。
控制类节点的复杂性:在于流程控制的复杂,比如并行节点,就比其他节点的控制流程复杂;
功能类节点的复杂性:在于功能本省想实现的功能,这和外部功能有关;
LevelNode和SkillNode这两类的节点会一直开发下去,除非游戏不扩展了。
所以现在我们只实现NormalNode相关的节点。
控制类节点实现
运行时环境为我们提供了两个功能:执行当前节点和寻找下一个节点。
所以我们的节点写法里面只需要针对这两个过程编写就可以了。
接下来开始具体节点编写。
顺序节点:按照编写的顺序执行节点直到全部执行完成为止。
上图可以看得出来节点的编写并不麻烦,相对来说还是很容易的。
单元节点:子节点中有一个执行失败此单元就执行完成。
循环节点:反复执行一个流程
否定节点:对子节点的运行结果取反
判断节点:根据需求去判断一个节点是否需要被执行
这里也顺便说说属性的设置:为了将调用接口统一成GET_PROP我们定义属性为标识、值和值类型的集合,这样在使用的时候就能统一了。
等待节点:设置一个等待时间,时间到执行完成。
到目前为止我们的控制类节点都不复杂,除了并行节点。
前面说到的节点都是一个行为树里面的节点,但是并行模式却要同时执行多个行为树:
代码部分:
打印节点:
基本节点都说了一遍接下来:事件和节点注册
上图是策划的行为脚本,也许是策划自己写的,也许是工具生成的,这个我们不关心,我们关注点怎么去将这个脚本解析成一颗树?
对于策划的提供的文件我们需要做两件事件:
- 注册事件;
- 给注册的事件绑定行为树根节点;
代码逻辑如下:
通过我们制定好的规则,一层层去像剥洋葱一样把将AI文件剥开。
然后通过父子兄弟建立联系,这样我们就能知道当前节点的运行位置了,然后运行完成之后根据具体的控制逻辑去寻找下一个节点。
关于事件注册:我们注册了事件和行为树绑定之后,外部系统只要触发这个事件,行为树内部就会执行绑定的行为树。
关于行为树中断:
每个事件都设置一个优先级,或者动态计算优先级,然后根据优先级去中断当前正在执行的行为树。
关于事件触发
某一个事件触发:比如战斗开始:那么就会触发绑定的行为树,而行为树的编写又可以根据具体的情况做很多改变,这样就能够轻松实现很多功能了。
既然我们有了关卡行为节点,那么在进入游戏的第一刻,场景中的所有物体,除了玩家控制的,应该都受到AI的控制,这样就能将游戏流程完全的控制住。