环境:Unity2017.4 语言:C#
总起:
上一章我们简单介绍了一下行为树,这一章带大家了解一下机制,最好是根据我的例子做一遍。
行为树是由Task任务节点组成的,而任务节点总共就四种分类:
- Composite,组合节点,将子节点进行一定规则的组合;
- Decorator,装饰节点,将一个子节点进行特定的操作;
- Action,行为节点,进行一个特定的操作;
- Conditional,条件节点,进行判断,决定后续节点是否执行。
上述的四种节点都有相应的类,并都继承于Task类,自己想写一个节点只要继承上述四种节点的类即可。
其中最常用到的是后两种节点,组合节点系统提供的基本够用,装饰节点个人比较少用到,而行为节点和条件节点基本上是要根据工程的不同进行重写的。
下面介绍一下节点的生命周期方法。
Unity大家都知道,继承MonoBehaviour的脚本有很多生命周期方法,Awake、OnEnable、Start,面试中总会被被问到。同样的,行为树的节点也都拥有它们的生命周期方法。
分别为(最重要的是前4个):
- OnAwake,在行为树启用的一瞬间被调用;
- OnStart,在节点正式执行之前被调用,通常用于重置变量;
- OnUpdate,节点的正式执行;
- OnEnd,节点执行成功或失败后执行;
- OnPause,行为树被暂停或恢复时执行;
- GetPriority,节点的权值,PrioritySelector的子节点才有用处(或其他类似的组合节点);
- GetUtility,节点的效用,UtilitySelector的子节点才有用处(或其他类似的组合节点);
- OnBehaviorComplete,行为树结束执行时才会执行;
- OnReset,用于重置公共变量;
- OnDrawGizmos,任务在场景编辑中显示的小图标;
- Behavior Owner,行为树的引用。
大概了解这些基础知识后,我们来创建几个节点看看效果。
一个例子:
我们先来看一个最简单的节点:
public class MyLogAction : Action
{
// 在行为树中最好都使用Shared类型,这样能方便变量的共享
public SharedString Content;
// 开始执行
public override TaskStatus OnUpdate()
{
// 打印内容
Debug.Log(Content.Value);
// 返回成功
return TaskStatus.Success;
}
}
注意Action是BehaviorDesigner.Runtime.Tasks命名空间中的,不要导错了。
等待Unity编译成功,编辑器中就自动有这个任务了:
创建这个任务:
接下来选中这个任务,在Inspector界面中填入想要打印的值:
运行就能看到效果了:
这边提一下使用SharedString的好处。如果直接使用string类型是下面的效果:
少了个有点点的按钮,这个按钮是方便节点使用公共变量的,比如在Varibales界面中创建了一个string变量,则当前的Log节点可以对该变量进行引用,当执行到Log节点时就会打印该公共变量。
一个更加复杂的例子:
再来一个牵扯到组合节点的例子:
这边我们使用到了Sequence的组合节点,该节点执行时会执行底下的条件节点,如果条件节点返回success,则继续执行下面的节点,如果返回failure,则整个Sequence节点的执行会停止并返回failure。
然后MyRandomConditional的内容如下:
public class MyRandomConditional : Conditional
{
public override TaskStatus OnUpdate()
{
if (Random.Range(0, 2) == 0)
return TaskStatus.Success;
return TaskStatus.Failure;
}
}
运行游戏,可以看到这次运气不太好,本次随机的条件执行失败了:
好的今天就到这边,下一次可能更加深入的探讨行为树的原理。