行为树的管理&操作
一、操作单颗树
这是我们项目里面,一个敌人绑定了行为树,自动创建的behavior tree 脚本:
将红框放大可以看到:
行为树组件包含以下几个属性:
那当我们有需要的时候,如何代码操作这些变量呢?
(1)我们必须先找到要操作的树
找树的方法1:定义一个Public的 BehaviorTree tree = new BehaviorTree();,然后面板拖拽赋值。
找树的方法2:定义一个privarte的 BehaviorTree tree = new BehaviorTree();,然后通过GameObject 的Find查找物体,然后获得物体上面的组件来得到的。
(2)代码操作该树
using BehaviorDesigner.Runtime.Tasks;//引用不可少 using BehaviorDesigner.Runtime; public class Tree : MonoBehaviour { public BehaviorTree tree = new BehaviorTree(); void Start () { tree.enabled = false; var a = tree.GetAllVariables(); tree.StartWhenEnabled = false; var b = tree.FindTasksWithName("AI_Daze"); } }
上面代码只是简单的演示一下,可以操作行为树的数据。其实 面板截图里面的所有变量都可以操作,除此之外,tree还有很多的属性和方法都可以操作。
二、管理所有树
当行为树运行时,将会自动创建一个带有行为管理器组件的新游戏对象,并且该对象上面绑有 behavior manager组件。此组件管理你场景中所有的执行的行为树
你可以控制行为树的更新类型,以及更新时间等等
Update Interval:更新频率
Every Frame:每帧都更新行为树
Specify Seconds:定义个一个更新间隔时间
Manual:手动调用更新,选择这个后需要通过脚本来调用行为树的更新
Task Execution Type:任务执行类型
No Duplicates:不重复
Repeater Task:重复任务节点。如果设置成了5,那么每帧被执行5次
BehaviorManager.instance.Tick();
此外,如果你想让不同的行为树都有各自独立的更新间隔的话,可以这样:
BehaviorManager.instance.Tick(BehaviorTree);
更多方法,请查看BehaviorManager类
自定义Task任务
一般复合类和装饰类的Task是够用的,甚至有些根本用不到,而具体的行为类Task和条件类Task从来都不能满足我们的需求,而且自己写这类Task可以很大程度的简化整个行为树结构。
自己写Task的步骤如下:
1.引入命名空间:
using BehaviorDesigner.Runtime; using BehaviorDesigner.Runtime.Tasks;
2.明确继承的Task类型:
1. public class MyInputMove : Action 2. public class MyIsInput : Conditional
3.知晓Task内部函数的执行流程:
观察上图就会发现和Unity中编写脚本大同小异,不一样的地方就是这里的Update有返回值,要返回该任务的执行状态,只有在Running状态时才每帧调用:
using UnityEngine; using BehaviorDesigner.Runtime; using BehaviorDesigner.Runtime.Tasks; public class MyInputMove : Action { public SharedFloat speed = 5f; public override TaskStatus OnUpdate() { float inputX = Input.GetAxis("Horizontal"); float inputZ = Input.GetAxis("Vertical"); if (inputX != 0 || inputZ != 0) { Vector3 movement = new Vector3(inputX, 0, inputZ); transform.Translate(movement*Time.deltaTime*speed.Value); return TaskStatus.Running; } return TaskStatus.Success; } }
总结
行为树的如下几种优点
> 静态性
越复杂的功能越需要简单的基础,否则最后连自己都玩不过来。
静态是使用行为树需要非常着重的一个要点:即使系统需要某些"动态"性。
其实诸如Stimulus这类动态安插的Node看似强大,但却破坏了本来易于理解的静态性,弊大于利。
Halo3相对于Halo2对BT AI的一个改进就是去除Stimulus的动态性。取而代之的做法是使用Behavior Masks,Encounter Attitude,Inhibitions。
原则就是保持全部Node静态,只是根据事件和环境来检查是否启用Node。
静态性直接带来的好处就是整棵树的规划无需再运行时动态调整,为很多优化和预编辑都带来方便。
> 直观性
行为树可以方便地把复杂的AI知识条目组织得非常直观。默认的Composite Node的从begin往end的Child Node迭代方式就像是处理一个预设优先策略队列,也非常符合人类的正常思考模式:先最优再次优。
行为树编辑器对优秀的程序员来说也是唾手可得。
> 复用性
各种Node,包括Leaf Node,可复用性都极高。实现NPC AI的个性区别甚至可以通过在一棵共用的行为树上不同的位置来安插Impulse来达到目的。当然,当NPC需要一个完全不同的大脑,比如100级大BOSS,与其绞尽脑汁在一棵公用BT安插Impulse,不如重头设计一棵专属BT。
> 扩展性
虽然上述Node之间的组合和搭配使用几乎覆盖所有AI需求。
但也可以容易地为项目量身定做新的Composite Node或Decorator Node。
还可以积累一个项目相关的Node Lib,长远来说非常有价值。