项目开始逐渐迁移到unity5上,原有用4的打包流程在5上依然是work的,基本是不用改代码的,但是5对打包做了一些改进,今天在考虑要不要改一下项目的打包代码,使用5的所谓的“新的方式”,但是仔细研究了一下,发现其实是没太大必要的,5的打包没解决什么根本问题,下面我对4和5的打包策略进行一下对比分析,并说一下目前大体的打包方法。
unity4的打包
unity4基本打包全是靠代码操作,代码使用诸如BuildPipeline.BuildAssetBundleExplicitAssetNames这样的函数来制定把某些资源打进一个bundle包,但是复杂的地方在于:
- 处理共用的资源,对于共用的资源我们不希望把他打进多个用它的包,例如资源bc共用a,那么我会先用BuildPipeline.PushAssetDependencies()把a放入堆栈,然后打a包,再打b和c,这样打b或c时如果堆栈中已经有了a,那么a的资源不会被打入bc,而是在b和c中建立一个到a的关联,这样我们在加载b时,先加载好a的包,加载b的包就能把b加出来了。但是假设如果这个程序里只有b依赖a,而没有其他任何资源依赖a,我们就完全可以把ab合在一个包里。
问题最复杂的地方在于对于一个大型工程,资源成千上万,依赖关系复杂,我们需要确定一个规则,哪些包可以打在一起,哪些要使用依赖,并给一个正确的push pop堆栈的顺序。看到一些项目需要配置表什么的,那个太不智能,我们的方法就是在打包之前遍历所有资源(所有是指除了代码的所有,包括模型 贴图 场景 shader 配表所有偶有)及其依赖关系,然后会生成几颗树(一个树林)的结构,这个结构里,父节点对子节点存在着依赖关系,然后我们会进一步精简这颗树,因为如果不精简就变成每个资源打一个包,会存在太多的包,我们迭代的把单节点的链条合并到其父节点中,并且消除树中的冗余路径,如a-》b-》c同a-》c同时存在时,我们会消除a-》c这个依赖。最终我们得到一个合并了节点的一些树,然后大体按照从树叶到树根的顺序用push pop打包(总的原则就是依赖的包一定要先在栈里,用完还要及时出栈,不然会影响打包速度) - 加快每次打包的速度,对于大型工程,每次打包的资源非常多,如果每次都全部重大,很耗时间,于是我们做了一套增量的打包,每次打包会记住md5,下次打这个资源时会查看他是否改动,对于没改动的资源就不重新打,当然这个是否改动不是只简单的看他的MD5是否改变,可能这次他的依赖关系变了,那么和包的内容也会变,所以还要考虑依赖的改变等情况。
- 在线更新,我们需要在每次打包后生成每个版本的所有包的信息,这样才能为用户正确的在线更新新的包下来,基本上会比较用户本地的包和最新服务器上的包的情况,启动游戏前更新到最新
- 资源加载,unity的ab包一个最大的缺陷是,对于一个ab包,两次从他解出的资源是两份内存,基于这个缺点,我们在加载资源时要有选择性的cache住一些bundle包,即加载好资源后不能unload,那么那些该cache呢,最完美的方法是实现一套自己的引用计数机制,ab包和资源asset之间一层计数,asset于使用的实例之间一层计数,当没有人使用这个asset时,该asset可以删除,并减少对其依赖的ab包的计数,而当一个ab包没有被任何asset引用时,则unload这个ab包。这样能保证三点:没有任何一个资源会被打到多个包里,没有任何一个资源在运行时是两份内存的,没有任何一个ab包当前是在浪费内存的,它cache着就说明有人在用它。很多团队的资源加载系统是做不到这三点的。
unity4给我们的工具就只有两个:一个是打包,一个是进出栈。所以我们生成最优化的打包树(上面1),增量打包(上面2)和更新(上面3),资源加载(上面4)都需要我们自己做工作,事实上这个工作量是很大的,而且会有着居多的坑在等待着您。索幸我已经在前面的项目就稳定下来这一套自己的打包系统了。
unity5的打包
最近我在想unity5 的新策略是不是可以优化一下我们现有的打包系统,不过还是比较失望。
unity5的几个最主要的改进是:
- 它允许你在编辑器上(当然代码里也行)指定某个资源应该打到某个包里:这个我认为没什么用处,因为及时有这个我们也不能指望策划或美术去制定哪个资源在哪个包里,因为哪个资源在哪个包应该是我们根据打包树算出来的,所有我们还是要根据打包树去在代码里设定资源和包的映射。
- 它obsolete了pushpop接口,就是他不需要我们自己在打包时处理进出栈来维护包的依赖关系了,只要告诉它要打哪些包,他自动为你安排最合适的打包顺序:我认为这个是有用的,因为自己处理是很麻烦的,但是我们的打包系统已经自己处理好了。
- 它自己加了增量打包,它本地记住了每次打包的一些文件信息,下次打包只打改过的资源:这个是有用的,不过我们也已经自己处理的增量打包,而且这个自己做也并不麻烦。
所以基于unity5,我们打算在现有基础上做的改进就是,用它的打包替代我们自己用push pop去维护打包顺序,并且用它的增量打包替代我们的增量打包。但是对于那些没有自己的打包系统的团队,这3点改进是微不足道的,因为他们还是要自己处理生成打包树,以及根据打包树去加载资源,这才是最复杂的事情。当然小的团队小游戏不在乎包大小内存就无所谓了,但是对于大型项目无论基于4还是5,完美的资源加载和打包还是需要大量的工作量的。