Skip to content

Unity3D 思考如何”填”资源打包的”坑”

Unity3D 思考如何”填”资源打包的”坑” published on Unity3D 思考如何”填”资源打包的”坑”有101条评论

unity47

最近一直在思考如何“填”Unity3D资源打包这个坑,这篇文章的目的是整理思路,所以正确与否就仁者见仁智者见智了。

首先说下资源打包的目的,我认为资源打包无非是为了以下几方面的目的:

  • 最重要的是使游戏资源可动态更新,而不用每次都走发布流程
  • 其次可快速解决一些因为资源带来BUG
  • 最后就是手动控制资源的使用,节约内存,提升游戏性能

我目前暂时想到这些,其他的目的暂时没想到,其他朋友想到的可以告知一下,我好添加进来。好了,基于打包的目的,我的思考出发点是Unity3D几个原生概念

  • Scene(场景)
  • Prefab(预制)
  • Asset(资源)

这几个东西其实是相辅相成的。

我对Scene(场景)的理解是用来保存相对静态的游戏对象,当然动态对象的实例也可以放里面,比如已经被做为Prefab(预制)的角色或模型的实例。我这里说的静态的游戏对象,其实主要是指场景中不动的、几乎不变化的物件,例如地形、房屋、树木、花草、山石、装饰物、常态粒子等等,其实Scene(场景)好比一个“房间”,里面可以放各种“家具”,场景就是用来保存这些“家具”的类型、组合方式、位置、旋转、缩放等这些基本信息的。

而Prefab(预制)呢,就是用来保存在场景中会动态创建的对象信息的,例如RPG游戏中的玩家角色、怪物、玩家的防具、武器等等。用类比的方式来讲,Prefab其实就是一个“模具”,根据同一个模具可以做出很多相同的“玩具”,这个“模具”保存了这个“玩具”是如何组合起来的,由哪些“零件”组成,也保存了这些“零件”的相对位置、相对旋转、缩放比例等信息等。总体来说我认为预制主要目的是用来保存需要在游戏中动态实例化对象的东东(当然静态实例化的对象也可以用这个来保存)。写着写着突然又想到一个更好的类比,程序猿一看就懂的:预制是你写的类,预制可以被实例化,就像你把类new出来一样。

Asset(资源)在Unity3D里面是一个很重要的概念,可以这样说构成游戏世界的80%的游戏对象都关联了一个资源。Unity3D中资源的类型很多例如:贴图、材质、模型、Shader、脚本、文本文件、声音、动画等,其实我们在Project面板下看到的所有东西都被称为资源。这些资源并不是一个一个独立的个体它们之间是可以存在依赖关系的,例如模型关联了贴图和材质可能还有动画。

插一句,在Unity3D中,选中一个目标资源,右键,便可以查看其依赖关系。dependencies

 

现在来思考打包方案,我先提出待解决的问题(要填的坑)

  • 同资源不能被重复打包或打包到多个AssetBundle里面
  • 打包后的资源可以独立更新
  • 加载要方便,不能而为了加载一个资源手写一堆预加载代码

然后是解决问题的思路(如何填坑)

  • 每个资源单独打包,这样做的目的是为了解决独立更新的问题
  • 按资源的依赖关系分级,从分级最低的开始打包,目的是为了避免资源被重复打包。比如,一个FBX模型,他依赖了材质、贴图等,其中材质又依赖贴图,而贴图不依赖任何东西,所以贴图这种资源的依赖分级就是最低的
  • 所有被打包的资源都需要被管理起来,包括资源的名称、打包后的名称、资源的依赖分级、打包时间、唯一标识、版本号等,保存一个列表文件中,方便读取和查找被打包的资源
  • 实现一个统一的资源管理器,目的是为了方便的更新资源、加载场景、实例化预制、将这些复杂的处理过程简化到极致。

大概的打包过程如下:

  • 预处理将要打包的目标,先处理要打包的场景,然后再处理场景中没有用到但游戏中要动态实例化的预制。需要说明的是,这里说的处理并不是指打包,而是将相关资源整理出来建立打包时需要的一些列信息。
  • 做场景预处理。先获取场景所依赖的所有资源,然后遍历这些资源,得到每个资源的依赖分级,因为有可能有同名资源,所以这时也要生成好每个资源被打包后的文件名,我想用“多级目录名_文件名”的方式应该可以保证其唯一性,例如static_texture_gun1_png.assetbundle。最后按依赖分级关系生成一个依赖文件,把之前整理出来的信息保存下来,这个文件不但会用于后面打包过程,也会用于运行期资源管理器加载场景时使用。需要注意的是,最后要把当前场景文件(*.unity)也要添加到依赖文件中,因为场景文件本身也需要打包的。正常来说对于每一个场景,都应该生成一个依赖文件。处理完一个场景后,要将这个场景的原始名和打包名称写到一个场景列表文件里,方便游戏运行期加载时读取。
  • 做需要被动态实例化的预制体预处理。这种预制体在开发的时候最好实现就放置在一个专用的文件夹下,以方便打包时的工作。和场景一样同样的,得到每个预制体的依赖资源,做好依赖分级处理,生成预制体的依赖文件。和场景一样,最后也要将这个预制体的名称写入到一个预制体列表文件里。对了,补充一下关于依赖文件最好也找个专用的文件夹保存,因为依赖文件最后也会打包成assetbundle文件发布。
  • 现在读取所有的依赖文件,在内存中生成一个待打包资源的列表,这个列表有清晰的分依赖分级关系,打包的时候就根据这个依赖分级来决定什么时候调用PushAssetDependencies()函数来建立依赖关系。为什么遍历所有依赖文件,目的是在于要在整理一次,剔除一下重复的资源,避免同一个资源被多次打包浪费时间。
  • 最后开始打包,根据上一步生成的待打包资源列表打包,打包文件存放也请指定好一个专用的文件夹。。
  • 打包完成后这里还需要生成资源更新文件,这个文件中保存了所有打包好的assetbundle文件的列表,以及这个assetbundle文件的唯一标识:比如MD5码、SHA码等、还有它的当前版本号。假如项目更新了,重头执行一遍打包过程,然后和上一次的这个文件做个比对,把变化的assetbundle文件升级版本号,然后放在服务端让客户端只下载最新的assetbundle文件。

 

原创文章,转载请注明: 转载自游戏无界·达秀的黑暗空间

本文链接地址: Unity3D 思考如何”填”资源打包的”坑”

本站作品除特殊申明外均为原创,采用知识共享署名-非商业性使用-禁止演绎 3.0 Unported许可协议进行许可。如果需转载请保持文章完整性和标明原文出处,禁止商业用途。