为了制作一个简单的怪物AI(回合制为什么也要用行为树啊啊啊啊啊),今天要被迫学习一波Behavior Designer了!
下载插件后一头雾水,不过好在插件内有一个详细的说明文档(Documentation)。不过全是英文文档,看起来很费时间,于是我在网上找到了一个翻译成中文的文档(有的代码是截图的很模糊,还好有原版文档可以两边对照着看):Behavior Designer 中文版教程。然后下面就写一点学习过程中用到的文档上的东西吧~
1.BehaviorTree与BehaviorManager
打开工具栏中的Tools/Behavior Designer/Editor可以打开行为树的编辑界面,选中一个GameObject后在编辑界面右键可以创建一个行为树实例。对应的会在GameObject上挂载一个BehaviorTree脚本,这个脚本用来管理整个行为树实例。
在游戏运行后,如果存在BehaviorTree实例且没有BehaviorManager实例的话,会自动创建一个全局的用来管理所有行为树的BehaviorManager实例。BehaviorManager中可以修改行为树的更新频率,默认是每帧更新,因为我们不需要每帧进行行为树的更新,所以这里改成了手动更新:
修改为手动更新后要通过代码调用下面的函数才会更新行为树的行为。(上面的是更新所有行为树,下面的是更新指定某个行为树)
BehaviorManager.instance.Tick();
BehaviorManager.instance.Tick(BehaviorTree);
2.编写自己的Condition与Action
由于插件写的非常牛逼,所以在自定义Condition和Action的时候变得异常方便,只要继承对应的接口,然后在代码里写一些类似unityMonoBehavior的生命周期函数就可以实现了:
Condition:
using BehaviorDesigner.Runtime.Tasks;
using UnityEngine;
public class TestCondition : Conditional
{
public int number;
public override void OnAwake()
{
Debug.LogError(number + "enter awake");
base.OnAwake();
}
public override TaskStatus OnUpdate()
{
Debug.LogError(number + "update");
return base.OnUpdate();
}
}
Action:
using BehaviorDesigner.Runtime.Tasks;
using UnityEngine;
public class TestAction : Action
{
public override TaskStatus OnUpdate()
{
Debug.LogError( "action update");
return base.OnUpdate();
}
}
有了这两段代码,在Behavior编辑器中右键菜单的Action和Condition页签中就会出现刚刚自己定义的类型了。刚刚的Condition中有一个额外的公共变量,这样在编辑Behavior的时候还可以根据不同的需求给相同的Condition不一样的变量值。
3.Variables
除了上面提到的Action与Condition中的变量值以外,BehaviorDesigner还提供了给BehaviorTree使用的公共变量。
这里可以添加针对整个BehaviorTree使用的变量(使用代码绑定行为树的目标或者做些其他的什么)。此外下面还有一个GlobalVariables,目前没有需求使用这个,不过应该是那种所有行为树都共用的变量吧~
然后接下来就是变量和我们的Condition或者Action结合操作了!
让我们稍微改一下之前的Condition:
using BehaviorDesigner.Runtime;
using BehaviorDesigner.Runtime.Tasks;
using UnityEngine;
public class TestCondition : Conditional
{
public int number;
public SharedInt sharedInt; //Add!!!
public override void OnAwake()
{
Debug.LogError(sharedInt + "enter awake");
base.OnAwake();
}
public override TaskStatus OnUpdate()
{
Debug.LogError(sharedInt + "update");
return base.OnUpdate();
}
}
然后把我们刚才index变量填充到Condition的SharedInt中。
最后添加一个修改变量的脚本
using BehaviorDesigner.Runtime;
using UnityEngine;
public class TestBehaviorTree : MonoBehaviour
{
public BehaviorTree bt;
private void OnGUI()
{
if (GUI.Button(new Rect(20, 40, 80, 20), "修改变量!"))
{
bt.SetVariableValue("index",1);
BehaviorManager.instance.Tick(bt);
}
}
}
点击ongui上的按钮后就会看到下面的log(输出了两次是因为我加了两个Condition上去emmm)
4.Composites
组合节点中必须要存在子节点,组合节点大概分为三种类型:Selector、Sequence、Parallel。他们的特性分别为:
Selector:选择执行,当执行到第一个成功执行的节点时,结束执行
Sequence:顺序执行,会将下面的节点依次执行,当全部执行成功或有执行失败时结束执行
Parallel:并行执行,会将下面的所有节点同时执行,多用于播放动画音效等
看了小半天文档就总结出这点东西,因为还没有具体落实到项目中,目前只是在看文档学习阶段,所以肯定有不少理解不深的地方,如果有大大看到了希望帮忙指正。后面落实到项目的时候如果遇到坑也会回来补充的!呐,马大内!