欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Unity Prefab中MonoBehaviour脚本修改带来的序列化问题

程序员文章站 2022-04-03 12:28:51
...

项目中出现的问题

载入一个prefab并实例化后,获取该prefab上挂载的一个MonoBehaviour组件,例如:

public class Foo: MonoBehaviour
{
	public bool newValue = true;
	
	void Awake(){
		Debug.Log(newValue);
	}
}

此时,Awake中的Log输出的是 false

分析原因

Foo组件中的newValue默认为true,但是Awake时为false。这说明序列化出了问题。但是打开该prefab进入编辑模式观察,发现 newValue的对勾是选中的。然后用文本编辑器打开该prefab,搜索newValue,并没有搜索到。这说明Foo组件在prefab中没有被正确的序列化。在prefab的编辑模式下看到的,newValue上的对勾,其实不是反序列化的结果,而是构造出来的Foo对象中的newValue默认值

结论

如果仅仅是修改了脚本,添加了新的可序列化的成员,刷新编辑器,甚至打开包含该脚本的prefab,都不会将新添加的成员值序列化到prefab中。只有当打开prefab编辑,且修改了prefab中的某一个属性时,prefab才会重新序列化。这样新添加的成员值才会被序列化到prefab文件中。

思考

Prefab编辑模式,只有当对prefab做出任何修改后才重新保存prefab文件,这是合理的。但是,打开prefab进行编辑时,Unity并没有识别出prefab中包含的脚本已经做了修改。我觉得作为引擎是可以做到这点的,只要付出一点点的代价,比如将prefab包含的脚本组件的md5值记录在prefab文件中,当打开prefab编辑时计算一下引用的脚本的md5,和保存在prefab中的md5值进行对比。另一个问题是,当脚本修改时,包含该脚本的所有的prefab和scene,是否需要自动刷新?我觉得全部自动刷新的代价比较大,且脚本修改是很频繁的动作,确实不能去自动刷全部。另外Unity是否保存了脚本被哪些prefab/scene引用的信息?我觉得没有。因为这样要保存的信息很多,且容易失去同步。但是可控的手动刷新应该被支持。

解决方案

当某个脚本被若干prefab/scene包含时,修改这个脚本就要注意这个问题了。一般来说,项目中的资源会有比较良好的组织,虽然Unity引擎本身并没有去管理脚本被哪些prefab/scene包含的问题。但是项目自己知道这个脚本可能被哪些目录下的一组prefab/scene包含。这样就可以创建一个工具,去有选择的刷新那些会被影响到的prefab/scene。
如果prefab数量不多,可以手动打开,任意改变某个组件的某个值再改回去,退出prefab编辑。这样该prefab就会重新序列化。

感悟

虽然这个问题是一个并不复杂的小问题,但是当在一个较大型的项目中,却容易引起特别隐晦的bug,会浪费大量时间去修改bug。因此需要在项目中精心管理资源和代码,规范工作流程,辅助以工具,将bug扼杀在萌芽状态,这是一个游戏开发主程的基本修养。