参考着目前最热门的两款商业引擎,unreal与unity3d,这两款引擎对“脚本”有着完全不同的处理方式。
Contents
Unity3d
在unity中,游戏C#脚本会被视为名为MonoScript的资产,对象均由反序列化器来创建,而并不去使用构造函数来初始化,用户需要在Awake中编写初始化代码。在编辑器中,资产路径有着另一种表达方式:GUID。有了GUID,可以摆脱掉资产移动造成的路径错误丢失引用等问题,但实际GUID仅在编辑器中用来代替路径使用,在打包后将不会再有GUID的概念。
unity中包括编辑器,所有基于UnityEngine.Object的对象都会有一个instance id,在编辑器中一些资产就已经被加载进内存并拥有instance id了,场景内的对象可以直接引用这个instance id并保存,在该对象加载时如果该引用没有被实例化,那么此时将会将该数据读取到内存。
脚本是资产也就意味着可以和其他普通资产一样在Assets中,不光是脚本是资产,dll也可以是资产。插件的内容可以直接放在Assets文件夹中,这样做看起来作为项目的一部分管理,但近年package包管理盛行,unity推出的packageManager打破了插件需要放在Plugins这一规则。比起放在plugins文件夹,package可以让项目管理更加模块化,利于更换维护。
UnrealEngine
在urneal中,代码就是代码,c++的脚本编译后在构造时对对象初始化,如在Actor构造函数内添加ActorComponent等功能。因此unreal的脚本不能像在unity里一样做到脚本的循环引用,因为对象的构造顺序是不确定的。而在构造函数中去设置对象的方式,也让程序变得非常的不稳定,以c++这门不安全的语言来讲,也许比起异常更好的方式就是崩溃,而ue也是这么做的,ue在启动时就会对c++类生成一个CDO对象,而这个CDO就是由类型构造而来,当在构造函数中读取了错误的资产引用等操作,就会使得UE编辑器无法启动,另外UE在一些情况下无法提供准确的错误堆栈信息,这使得错误查找变得更加麻烦。从游戏业务逻辑与编辑器角度来看,绑定一门更加安全好用的语言应该是最佳选择。
对于路径来说,unreal对插件脚本和资产的处理则是使用了一种类似路径映射的概念,路径是虚拟的,不是一个绝对的文件夹。用路径索引位置有好处也有坏处,好处就是可以更加直观的知道使用的资产,并且可以在代码中体现,而缺点也显而易见,很难去修改文件名与文件位置,当文件名一旦在引擎外被修改,那引擎是没有办法知道的,会造成资产引用丢失的问题,ue使用重定向器来解决这个问题,尽管如此,博主觉得依旧不够优雅。
那么我们能互换这两种方式吗
如果unity的脚本以unreal的模式来使用的话,首先最重要的一个问题就是,unity主要是以继承MonoBehaviour来进行开发的,GameObject可以看做是一个节点,无法继承和承载具体的功能
这里其实更多的可能取决于语言的不同,unity将脚本视为资产也对C#本身进行了限制,例如继承MonoBehaviour的类需要和文件名一致。
语言脚本的资产化
将脚本语言像unity那样看做资产是我最开始对引擎设计的设想,但后来一个不得不面临的问题就是作为逻辑语言的c++,首先想到的就是像unity那样将脚本直接放在Assets中,编辑器会收集扫描文件夹下的所有.h与.cpp文件生成cmake解决方案,然后将这些头文件所在的路径都加到cmake的include中,这样在项目的任何地方都可以直接使用其他类型,以免破坏使用guid的好处而改动#include路径。当cmake收集构建所有信息之后,就去生成visualstudio的sln解决方案。
另一种是将脚本作为单独类型的放在Source文件夹而不是放在Assets内,并不把脚本看做和普通资产一样,但这么做想表现的资产就需要给每个Asset脚本分配guid以及同样普通资产其他信息,而程序构建角度来讲,这样依旧可以使用常规的头文件路径和程序组织方式,
上述所说因c++构建编译时间对于快速迭代来说时间过长无法满足现代需求,而如果很想或者必须这么做的话,那么以上两种方案供参考。
文章评论