Unity AI 行为树

1、行为树是一种逻辑工具,对工具的学习方法肯定是实用优先。

特地说这个是因为Behavior Designer提供的功能其实比我们要用的多。作为使用者,务必记住要先把基本功能搞清楚,在初期那些不必要的高级功能只会把我们的思路搞乱而已。设计AI本身已经是很烧脑的工作,不建议使用一些很不直观的修饰器和组合器给自己添乱。而且基本功能已经足够我们组合出非常复杂而强大的行为树了。 :)

2、行为树中的节点,会在某一帧中被调用,然后立即得到一个结果:成功Success、失败Failure、运行中Running,只能取三者其一。然后组合器和修饰器会根据返回值进行下一步,这是行为树的基本逻辑。

3、节点不是多线程并行的,被调用的节点都必须迅速执行完毕并返回Running、Success或者Failure。所有事件就算是同时发生,也总有先后之分。


二、组合器的详细介绍

注:本段先略读一遍,然后下一段咱们会做实验,边实验边阅读效果更佳。

Sequence 串行的AND

Sequence 类似于编程语言中的"&&"符号,它从左到右,每帧只执行一个子节点。

1、如果当前子节点返回Running,那么Sequence也返回Running。下一帧继续执行当前这个子节点。

2、如果当前子节点返回失败,那么Sequence节点本身返回失败。

3、如果当前子节点返回成功,如果还有下一个子节点,那么Sequence本身返回Running,下一帧会切换到下一个子节点; 如果所有子节点都完毕了,则Sequence节点返回成功,整个节点结束。

Selector 串行的OR

Selector与Sequence执行顺序相同,逻辑正巧是“||”的逻辑。它也是从左到右,每帧只执行一个子节点。

1、如果当前子节点返回Running,那么Selector也返回Running。下一帧继续执行当前这个子节点。

2、如果当前子节点返回失败,那么Selector节点本身返回Running,下一帧执行下一个子节点;如果所有子节点都失败了,就返回失败。

3、如果当前子节点返回成功,那么Selector返回成功。

Parallel 并行的AND

Parallel 从返回值来看它是 “&&” 逻辑。与Sequence的区别是,在每一桢,它都执行所有子节点一次~~。

1、所有子节点都Running,那么Parallel节点也返回Running。

2、有任何一个节点返回失败,那么Parallel立刻结束,返回失败。还处于Running的子节点也会终止(从界面上可以看出,正在Running的被假设为失败)。

3、有任何一个节点返回成功,那么该子节点下一帧就不会被调用了,但是Parallel本身仍然返回Running,直到所有子节点都返回成功,Parallel才返回成功。

Parallel Selector 并行的OR

Parallel Selector 从返回值来看是 “||” 逻辑。它是并行的,每一桢执行所有子节点一次~~。

1、所有子节点都Running,那么Parallel Selector节点也返回Running。

2、有任何一个节点返回失败,那么Parallel Selector 本身返回Running,直到所有子节点都失败了,它才返回失败。

3、有任何一个节点返回成功,Parallel Selector 直接返回成功。

好的,我们解释了四种最基本的节点,只需它们就足够组成行为树的骨架。下图是Composites全图,我给它们分了组,前面介绍的就是最上面一排基本组。

Unity AI 行为树_第1张图片


其它节点就容易了,我们继续看看:

Random Sequence 变体的Sequence(串行)

Sequence是从左到右串行,Random Sequence 也是串行完全一样,只是它从还没执行过的N个子节点中随机挑选一个执行。

Priority Selector, Random Selector 变体的Selector(串行)

这二者是Selector的变体,也都是串行。分别是根据优先级挑选、随机挑选、自定义挑选顺序。

★ 再强调一下,串行情况下,如果有节点还在running,那么肯定先执行running的节点。“挑选”的意思是说,在没有running的节点时,从还没执行过的节点中,根据规则挑出一个。

Selector Evaluator, Utility Selector 特殊顺序的Selector

这两种类型的特殊之处在于:在每一帧,都要重新计算子节点的优先级或者效用,就算节点正在running,也有可能因为优先级变化而切换节点。它们既不是并行也不是串行。

Utility Selector 是一种选择器,它是基于“Utility”也就是“效用”进行选择,用在《模拟人生》这种游戏中会非常有效,就是当你面对吃法、睡觉、上厕所这三件事时,你选效用最大的那一件事去做即可,而且如果有必要可以随时终止当前正在做的事情。

Selector Evaluator 涉及到优先级的问题,暂且不表。


三、组合器和返回值实验+详解

前面的讲解过于抽象,咱们可以做下面这样的一个行为树,挂在任意一个GameObject上面,直观感受各种组合器的特性:

Unity AI 行为树_第2张图片

说明:新建GameObject到场景中,并为它创建一个行为树如上图。四个动作节点是Wait节点,在行为树的Inspector窗口里,把Wait节点的等待时间分别改为2、1、2、3秒。然后执行效果如下:

如意上面的CharacterData chaData,这个就是我的NPC角色身上的一个脚本组件。用上面的写法,就可以在动作脚本中访问其他脚本的变量或者调用角色的函数了:

// 还是FireAction的OnUpdate函数
    public override TaskStatus OnUpdate()
    {  // 调用角色的方法
        chaData.Fire();
        return TaskStatus.Success;
    }

到底哪些函数和变量放在角色脚本中,哪些函数和变量放在行为树的动作脚本中?这是一个工程问题了,没有统一的方法。

个人建议:所有角色通用的变量和方法,放在角色脚本中。因为即使不用Behavior Designer插件,这些变量和方法也是有用的。而只用于AI的变量,放在行为树的Variables里面即可,由专门负责AI设计的人员维护。例如:角色移动速度、开火CD时间,都是角色本身的变量。而发现敌人的transform、距离敌人的距离,如果只在AI逻辑中用到,就应该放在行为树中。

★ 也有办法在角色脚本中访问行为树的变量,可以查阅官方文档和资料。但是我们尽可能避免这种用法,这种反向耦合对项目整洁不利。


还有修饰器的作用就不再详细表述了,大概列举如下:

  1. Inverter:条件判断或动作的返回结果取反,成功变失败,失败变成功,Running不变。
  2. Reapter:循环执行,可以调节循环次数等参数。
  3. Return Failure:返回值无论成功或失败都返回失败,但Running还是Running。
  4. Return Success:同上,相反。
  5. Until Failure:循环直到失败,换句话说如果成功就再次执行子节点。
  6. Until Success:同上,相反。

还有4种其他装饰器自行查阅。


四、变量应当保存在行为树中,还是角色脚本中?

思考这样一个问题:如果我们不用Bahavior Designer插件,那么脚本中也有各种角色相关的参数和变量,而如果用了插件,那么也可以把变量放在行为树里面,就好比之前用过的SharedTransform等等变量。

选择多了麻烦也多,到底把变量放在角色脚本中还是行为树里面呢?好在有办法可以在行为树中访问角色的变量,这样一来还是比较方便的。

例如,AI角色开火动作的脚本:

public class FireAction : Action
{
    // The transform that the object is moving towards
    CharacterData chaData;

    public override void OnAwake()
    {
        chaData = gameObject.GetComponent<CharacterData>();
    }
}

如意上面的CharacterData chaData,这个就是我的NPC角色身上的一个脚本组件。用上面的写法,就可以在动作脚本中访问其他脚本的变量或者调用角色的函数了:

// 还是FireAction的OnUpdate函数
    public override TaskStatus OnUpdate()
    {  // 调用角色的方法
        chaData.Fire();
        return TaskStatus.Success;
    }

到底哪些函数和变量放在角色脚本中,哪些函数和变量放在行为树的动作脚本中?这是一个工程问题了,没有统一的方法。

个人建议:所有角色通用的变量和方法,放在角色脚本中。因为即使不用Behavior Designer插件,这些变量和方法也是有用的。而只用于AI的变量,放在行为树的Variables里面即可,由专门负责AI设计的人员维护。例如:角色移动速度、开火CD时间,都是角色本身的变量。而发现敌人的transform、距离敌人的距离,如果只在AI逻辑中用到,就应该放在行为树中。

★ 也有办法在角色脚本中访问行为树的变量,可以查阅官方文档和资料。但是我们尽可能避免这种用法,这种反向耦合对项目整洁不利。

参考:
https://zhuanlan.zhihu.com/p/29366677
https://zhuanlan.zhihu.com/p/29598709

参考工程:

http://pan.baidu.com/s/1pLDSWcz

你可能感兴趣的:(UNITY,unity,AI)