• QQ
  • nahooten@sina.com
  • 常州市九洲新世界花苑15-2

游戏开发

常州手游开发-Unity5资源管理和增量更新

原创内容,转载请注明原文网址:http://homeqin.cn/a/wenzhangboke/jishutiandi/youxikaifa/2019/0314/412.html

常州手游开发-Unity5资源管理和增量更新

 

 

  • Unity自动打包资源是指在Unity场景中直接运用到的资源会随着场景被自动打包到游戏中,这些资源会在场景加载的时分由unity自动加载。这些资源只需放置在Unity工程目录的Assets文件夹下即可,程序不需求关怀他们的打包和加载,这也意味着这些资源都是静态加载的。但在实践的游戏开发中我们普通都是会动态创立GameObject,资源是动态加载的,因而这种资源其实不多。

  • Resources资源是指在Unity工程的Assets目录下面能够建一个Resources文件夹,在这个文件夹下面放置的一切资源,不管能否被场景用到,都会被打包到游戏中,并且能够经过Resources.Load办法动态加载。这是平常开发是常用的资源加载方式,但是缺陷是资源都直接打包到游戏包中了,没法做增量更新。

  • AssetBundle资源是指我们App开发培训能够经过编辑器脚原本将资源打包成多个独立的AssetBundle。这些AssetBundle和游戏包是别离的,能够经过WWW类来加载。AssetBundle的运用很灵敏:能够用来做分包发布,例如大多数页游资源是随着游戏的过程增量下载的,或者有些手游资源过大,渠道请求发布的包限制在100M以内,那只能把一开端玩不到的内容做成增量包,等玩家玩到的时分经过网络下载。AssetBundle 也能够用来做我们下面讨论的自动增量更新。

Unity5相比之前的版本,AssetsBundle的打包过程有所简化。之前打包需求经过代码来设置需求打入包的资源并本人树立包的依赖关系,Unity5能够经过每个资源Inspector底部的AssetBundle下拉来指定该资源要打入哪个包,不指定就是不打包。打包过程只需求BuildPipeline.BuildAssetBundles一句话就行了,Unity5会依据依赖关系自动生成一切的包。每个包还会生成一个manifest文件,这个文件描绘了包大小、crc考证、包之间的依赖关系等等,经过这个manifest打包工具在下次打包的时分能够判别哪些包中的资源有改动,只打包资源改动的包,加快了打包速度。manifest只是打包工具本人用的,发布包的时分并不需求。

关于自动生成依赖关系这个有必要提下,Unity的确会自动给你树立依赖关系,前提是你依赖的资源必需曾经在Inspector中设置了BundleName。假如没有,Unity会把这个公用的资源反复打到多个用到的包中,由于这个公用资源不在一个独立的包中,Unity也不会智能地给你发现它是公用的,然后生成一个公用包。更深的坑在于,假如你公用的是一个FBX模型,你只给这个模型设置BundleName还不行,它用到的贴图,材质都要设,否则模型是公用了,贴图没有公用,结果贴图还是被打包到多个包中了。所以常州网站开发培训设置BundleName这个工作最好还是由编辑器脚原本完成。

计划

 

 

Unity提供的就这些了,下面就本人发挥:如何做一个便当的资源管理计划,既能够开发时便当,又能够便当发布更新包呢?开发过程全用AssetsBundle是不适宜的,由于开发中资源经常添加和更新,每次添加或者更新都生成一下AssetsBundle才干运转是很费事的。而且我们要做的是自动更新而不是分包下载,这也就是说在发布游戏的时分这些资源应该都是在游戏包中的,所以他们也不该从AssetsBundle加载。

剖析完需求,计划也就出来了:资源还是放在Resources下面,但是这些资源同时也会打包到AssetBundle中。代码中一切加载资源的中央都经过本人的ResourceManager来加载,由ResourceMananger来决议是调用Resources.Load来加载资源还是从AssetsBundle加载。在开发环境下(Editor)这些资源显然是直接从Resources加载的,发布的完好装置包资源也是从Resources加载,只要当有一个增量版本时,游戏主程序才会去效劳器把增量的AssetBundle下载下来,然后从AssetBundle加载资源。

完成

 

 

完成中我们首先要思索的是AssetBundle的粒度,即常州企业培训每个AssetBundle包含几资源。增量包的最小粒度就是AsssetBundle, 假如单个AssetBundle过大,只需这个AssetBundle中有一个资源改动了就需求重新下载整个AssetBundle,糜费流量和玩家的等候时间;假如单个AssetBundle过小,极端状况是每个资源一个AssetBundle,固然完成了更新最小化,但是带来了额外开支:AssetBundle自身也是有大小的,而且查找加载AssetBundle也是需求时间的。大家都往U盘里面拷过东西,拷一个1G的文件比拷1千个1M的文件要快很多。比拟合理的做法是依据逻辑来,例如每个角色能够有独立的AssetBundle,公用的一些UI资源能够打到一个AssetBundle里面,每个场景独立的UI资源能够打成独立的AssetBundle。这样做资源预加载的时分也便当,每个场景需求用到几个Bundle就加载几个Bundle,无关的资源不会被加载。

下面要思索的是如何来肯定一个资源是从Resources加载还是AssetBundle加载。为此我们需求一个配置文件resourcesinfo。这个文件随打包过程自动生成。里面包含了资源版本号version,一切包的名字,每个包的HashCode以及每个包里面包含的资源的名字。HashCode直接能够从Unity生成的manifest中得到(AssetBundleManifest.GetAssetBundleHash),用来检查包的内容能否发作变化。这个resourceinfo每次打包AssetBundle时都会生成一个,发布增量时将它和新的Bundle一同全部复制到效劳器上。同时在Resources文件夹下也存一份,随完好装置包发布,这就保证了新装置游戏的玩家手机上也有一份完好的资源配置文件,记载了这个完好包包含的资源。

当游戏启动时,首先常州软件技术培训恳求效劳器检查版本号,前端用的版本号就是Resources下面的这个resourcesinfo中的version。效劳器比对这个版本号来通知前端能否需求更新。假如需求更新,前端就去获取效劳器端的新resourcesinfo,然后比对里面每个bundle的HashCode,把HashCode不同的bundle记载下来,然后经过WWW类来下载这些发作改动的bundle,当然假如效劳器版的resourcesinfo中包含了本地resourceinfo中所没有的Bundle,这些Bundle就是新增的,也需求下载下来。一切下载完成后,前端将这个新的resourceinfo保管到本地存储中,后面前端的一切操作都将以这个resourceinfo为准而不再是Resources下面的resourceinfo了。Resources下的resourceinfo能够退出历史舞台了,除非一种状况:本地存储的resourceinfo被以为删除了。手机端玩家清算应用的数据就会形成下载的bundle以及resourceinfo被删除。没关系,这时分前端由于找不到外部的resourceinfo了,还会运用Resources下面的resourceinfo和效劳器比对,把新的bundle重新下载下来。

如今从哪里加载资源就很明白了:ResourceMananger先读取resourcesinfo,晓得了游戏中一切的Bundle和每个Bundle包含的资源,然后去外部存储查找这些Bundle能否存在,假如存在,就记载下这个Bundle的资源应该从外部的AssetBundle加载,假如不存在,就从内部的Resources加载。在开发过程(Editor)中,由于不存在外部存储的bundle,资源自然都是从Resources加载的,到达了我们开发便当的目的。这个过程隐含了一点:不是一切的资源都需求有BundleName而被打包到AssetBundle中,游戏内不需求后续更新的资源就不要设置BundleName,它们不会被打包更新,这样的资源ResourceManager在resourceinfo中是找不到的,直接去Resources文件夹下面读取就行了。

加载AssetBundle,我们直接运用WWW类而不用WWW.LoadFromCacheOrDownload, 由于我们的资源在游戏开端的时分曾经下载到外部存储了,不要再Download也不要再Cache。留意WWW类加载是异步的,在游戏中我们需求同步加载资源的中央就要留意把资源预加载好存在ResourceManager中,不然等用的时分加载肯定要写异步代码了。大局部时分我们应该在一个场景初始化时就预加载好一切资源,用的时分直接从ResourceManager的缓存取就能够了。

资源加载卸载

 

 

最后常州平台运营简单说下资源的加载卸载,这个网上也有很多文章引见。 

从我了解来看Resources是一个缺省自动打包的特殊AssetBundle。无论从WWW还是AssetBundle.CreateFromFile创立AssetBundle其实是创立了一个文件内存镜像。这时分是没有Asset的。AssetBundle.LoadAsset 和Resource.Load才真正创立出了Asset,而Instaniate复制了这个Asset。留意这个复制有两种,学C++的都晓得浅拷贝和深拷贝,这里的复制有的是正真的复制,有的是援用。为什么要这样呢?由于有些游戏资源是只读的,像贴图Texture,这么大而且只读,当然不需求再去完整复制一份。但像GameObject这种资源它的属性是能够经过脚本改动的,必需要复制一份。所以一个资源从AssetBundle到场景中被实例化,其实有3块内存被创立,这3快内存的释放是有不同办法的。

  • 文件内存镜像是经过AssetBundle.Unload(false)来释放的。

  • Instaniate出来的Object内存经过Object.Destory来释放。

  • AssetBundle.Unload(true)不单会释放文件内存镜像,还会释放AssetBundle.Load创立的Assets。这个办法是不平安的,除非你能保证这些Assets没有

  • Object在援用,否则就出问题了。

  • Resources.UnloadAsset和Resources.UnloadUnusedAssets能够用来释放Asset。

这是老Unity的图,Unity5曾经把AssetBundle.Load 改成了AssetBundle.LoadAsset。这个改动让我们更明白了Load出来的是Asset这块内存区域。什么时分把Resource.Load也改了吧。

留意事项(坑)

 

 

  • Resources.Load办法传入的资源途径需是从Resources文件夹下一级开端的相对途径且不能包含扩展名;而AssetBundle.LoadAsset办法传入的资源名需是从Assets文件开端的全途径且要包含扩展名。途径不辨别大小写,倡议全用小写,由于AssetBundle.GetAllAssetNames办法返回的资源名都是小写的。

  • Unity5打包AssetBundle时会自动处置依赖关系,但是在运转时加载的时分却不会,程序需求本人处置,先加载依赖包。

  • AssetBundle.CreateFromFile不能加载紧缩过的AssetBundle,所以我们只能用WWW来异步加载AssetBundle。

  • 目前我用的Unity5.0.2f1的Resources.Load办法在手机端比原来慢了很多,假如以前能够不缓存每次用的时分都调用Resource.Load如今就不行了。频繁的调用会招致明显的性能开支,不晓得是不是Bug。


上篇:上一篇:常州手游开发-U3D客户端框架:UI框架
下篇:下一篇:常州手游开发-AS导出jar包并在U3d中使用