Behavior Designer全局变量的同步原理

Behavior Designer全局变量的同步原理

Behavior Designer 我一般简称为BD

一款广受好评的行为树Unity插件

上周包括今天一直都在研究这件事情

被折磨了好几天后算是找到了一个比较和合理的解释

所以决定好好记录下来 也算没有虚度光阴


BD有局部变量和全局变量之分

局部变量只能在一棵树上使用 全局变量可以让多棵树同时使用

但不管是局部变量还是全局变量 它们都继承一个共同的类 SharedVariable

BD对于可以把值关联到面板上的赋值的变量称为SharedVariable 也就是共享变量

SharedString SharedBool等等都是继承了这一个类

通过属性Value的Get Set对保护的泛型成员mValue的值进行修改

再通过mValue这个值进行值传递

而对于全局变量 每次通过SetString或者GetRandomString赋值都会改变面板上关联的值

到这里就会出现上周提出的问题 全局变量的共享机制是怎么实现的呢?


我们先从头回顾一下从编辑器到运行时的过程

全局变量主要由一个继承了ScriptObject和IVariableSource的单例类GlobalVariables来控制

内部有一个 List<SharedVariable>mVariables 通过属性Variables也可获取

还有一个索引字典 Dictionary<string, int> mSharedVariableIndex

反序列化的时候就会对这个列表做一次赋值 同时更新这个索引字典

方便之后拿取的时候可以快速通过名字获取到对应的索引继而拿到对应值


全局变量的创建和修改都在GlobalVariable这一窗口中进行

修改后并不是自动保存 而是留下了”脏”标记(SetDirty)

这样Unity就会显示未保存的*号 只有当你ctrl+s才会序列化到硬盘中

保存的位置在Plugins/Behavior Designer/Resource/BehaviorDesignerGlobalVariables.asset


局部变量的创建和修改则是在树的Variable窗口中进行

基本与全局变量相同 只不过保存的位置是跟随树

假如这棵树是挂载在场景上的某一物体 那么数据将会保存在场景的.unity文件中

如果这棵树被导出成外部树 那么数据就会保存在树的.asset文件中


对于一个变量来说 序列化通常会包括Type Name isShared isGlobal XXXmValue这些参数

XXX在这里代指它的类型 例如说测试中最常会用到String 那么这里拼接就是StringmValue

而对于一个任务来说 要序列化的东西就更多了

BD把任务分两部分来存 一个是EntryTask 一个是RootTask 这俩底下都有若干NodeData

NodeData会保存节点的Offset(偏移量或者说位置) ID Name Instant 以及若干变量

当我们在变量的下拉窗口里选择了要关联的值后 不管是局部还是全局

都会在序列化NoteData的时候把面板上关联的变量值拷贝一份到自己的变量上

Name的数据就是在这个时候保存的 表现在文件里json序列化后的部分

至于为什么要包括这么多的数据 我认为是因为有的任务变量并没有关联局部或者全局

而是一个该类型的数据 如果存储的时候不把其它类型补齐 反序列化的时候就会有问题

当然我觉得在反序列化的时候指定默认值也是一样的 所以这一点还待讨论研究


接下来把视角转回到运行时

当按下运行的按钮 BD会反序列化树 节点 变量进程序中

然后遵循BehaviorManager的要求按tick或者按帧开始执行

虽然大家都继承了同一个SharedVariable

但是实际上还是不同的对象

A.Value = B.Value 是A的Set = B的Get

在反序列化的时候 任务里的变量如果关联的是全局变量

就会被赋值对应列表里的变量

反序列化树的变量的时候会判断反序列化的变量数据里IsGlobal这一项是不是为True

如果为True的话就会在读取好的全局变量列表里通过Name找有没有这样的变量然后赋值

(JsonDeserialization的338行起 如果全局变量列表为空会优先执行Global的初始化)

通过这样的操作 任务的变量和GlobalVariable的mVariable列表建立了联系

当你修改任务的变量 实际上是在修改mVariable里的值

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注