Unity3D Behavior Designer 行为树3 不能被Disable的BehaviorManager及其神秘的TaskExecutionType

Posted 暗光之痕

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Unity3D Behavior Designer 行为树3 不能被Disable的BehaviorManager及其神秘的TaskExecutionType相关的知识,希望对你有一定的参考价值。

环境:Unity2017.4 语言:C#

 

总起:

今天想要探讨一下BehaviorManager的一些实现细节。

 

这篇文章并不是单纯的新手教程,很多基础概念在文章内不会过多的赘述。内容根据一些疑惑和问题,写一些思考和解决问题的手段。当然最终是会有结论的。

 

废话不多说,直接进入正题。

 

不能被Disable的BehaviorManager?

BehaviorManager是一个Instance,场景中没有的话就会生成,把这个东西拷贝下来,随便把玩几下。突然发现EveryFrame模式下,BehaviorManager不能被Disable,而其他两种模式下不能被Enable。

 

这是什么情况?

 

我们先在OnEnable和OnDisable的函数中打上Log,运行状态时结果如下:

 

我们可以看到BehaviorManager的Editor脚本调用了UpdateIntervalChanged,致使脚本根据当前的状态将enable强制设置为true了。

 

其实还有一些细节反映了是BehaviorManager Editor脚本的锅,因为在非运行状态下,我们虽然Disable了脚本,但看不到Log的输出,因为该脚本没有加ExecuteInEditMode标签,所以在Editor下并不会运行,既然脚本不会运行,那么这锅也只有其Editor脚本来背了。

 

我们赶紧去找一下Editor脚本。

 

哎哟,小样儿,居然还是dll,反编译出来,我们果然看到了Editor脚本中会一直调用set_UpdateInterval方法:

 

这下真相就大白了,但是仔细想想为什么要这么做呢?

 

Disable掉脚本或Enable脚本的区别就在于Unity生命函数的调用上。难道是EveryFrame需要使用Update更新行为树,而其他两种状态不需要,则将其Disable掉了?

 

查看BehaviorManager脚本,果然:

 

上面是EveryFrame的更新,那么其他两种状态时怎么更新的呢?

 

可以看到在Awake中调用了该函数,在SpecifySeconds启用了一个协程开始更新行为树,而Manual手动状态时完全不更新的。

 

TaskExecutionType有什么用?

BehaviorManager的UpdateInterval很好理解,是更新的周期,每隔多少时间Tick行为树一次。

 

但是下面的Type,我看了Doc文档和网上博文也不是很了解。

 

现在就让我们来探究一下吧。

 

其实大家估计跟我一样,第一眼看上去感觉这个就是限定了一次Tick执行中最多执行的Task数量。

 

事实似乎就是如此(我让很多个输出22的Log顺序运行,Tick的间隔时间为1秒,Tick最大的Task数量为2):

 

每次Tick发现还有更多的Task时发出了警告并跳出了执行,那么就是每次执行两个。

 

但是执行的速度也太快了吧!可以看到第一执行后的0.2秒就开始执行了第二次,我明明设置的是1秒。

 

我尝试着多建了几个Log Task节点,发现过了几次执行后,每次的间隔就变成1秒了。

 

并且这也不是必现的。

 

经过了1个小时的仔细总结规律,发现了只有当我选中BehaviorManager时会出现以上情况,而不选中即Inspector面板中没有出现BehaviorManager这个脚本时就不会出现这个BUG。

 

我好像发现了什么不得了的东西。

 

赶紧在UpdateIntervalChanged产生协程的方法中打上了Log:

 

果然是BehaviorManager的Editor脚本在刷新UI时重开了协程。

 

又是你,果然这锅还是得由你来背……

 

所以大家记得在运行行为树时不要选中BehaviorManager。

 

回到我们最初的问题,也就是说这个Type指定是运行Task最大的数量,但是NoDuplicates是什么?

 

我们先来看一下官方给的文档,实际上他举了个例子,正是这个例子让我产生了疑惑。

 

它说使用一个Repeater节点,让他循环5次,子节点是一个PlaySound,也就是循环执行PlaySound五次。那么Type设置为NoDuplicates时,每次Tick会执行一次PlaySound,而Type设置为Count=5时,一次Tick会执行完所有的5次循环。

 

如果单纯的按照以上来结果来看,就是Count=1嘛,所以仅仅是一种方便吗,用NoDuplicates代表Count=1?

 

不,肯定不是。因为如果我们使用的是顺序父节点,那在NoDuplicates的情况下5个是一起执行的。

 

What? 这是什么鬼?

 

我们来梳理一遍:如果设一次执行为一个父节点执行完所有子节点,假设Count代表的是一次执行的次数,那么NoDuplicates确实代表的是Count=1的情况了。但是这个Count同时包含了最大Task执行数量的含义。

 

所以总结一下NoDuplicates代表的是一次执行,而Count可以跨越多个一次执行,直到行为树执行满它所设定的Task数量。

 

小作业

留一个小作业,让大家思考一下。我们知道GameObject在Inactive的状态下是不会调用Awake函数的,BehaviorManager的Awake脚本会将instance进行赋值,那么如果我们将它的GameObject设置为Inactive运行行为树会出现什么情况呢?大家可以尝试一下哈。(答案在下一篇中揭晓)

 

内容的转变

本来这部分想写在开头的,想想一进来看到这个也不太好,跟文章内容完全没有关系,不感兴趣的同学可以直接跳过。

 

之前写了很多上手Unity插件的文章,这几篇行为树的文章也不例外,但随便一搜,这类文章就是铺天盖地,还有各类视频,生怕读者哪个按钮找不到了搜索又要搞半天。

 

其实个人以为新上手一个插件最好的就是视频,按照视频的步骤一步步往下走,信息量大,老师没讲解清楚的,回头再仔细看一下操作就行了。

 

而博文写这类教程,需要非常详细一个步骤,如果没有照顾到一些细节,读者可能看的一头雾水。 “我明明是这么做的呀,怎么不行?”之类的情况就会发生。写得太多,内容太冗余,又不利于仅仅想要了解某些细节的读者,浩瀚大海中找一粟困难至极。

 

有些繁复的内容记录下来当做笔记确实也不错,不过我以后的文章会更加侧重于一个点的描写,而不是从头到尾铺开来讲。针对某个脚本,探讨他实现的细节,一些有趣的地方。

以上是关于Unity3D Behavior Designer 行为树3 不能被Disable的BehaviorManager及其神秘的TaskExecutionType的主要内容,如果未能解决你的问题,请参考以下文章

Behavior Designer扩展

Behavior Designer知识点

Behavior Designer中的内置消息机制

Behavior Designer中Wait节点的坑

基于行为树的AI 与 Behavior Designer插件

Unity3D Substance designer Sub 欧洲小镇场景制作视频教程 中文字幕