zoukankan      html  css  js  c++  java
  • Unity资源 ----加载最好需要做哪些事

    先上图解

        

    一.基本关键词

        1)AssetBundle:一种保存“一个或多个资源的转变为某种利于传输等的特殊格式(二进制之类)”的文件。(我这边是使用Unity制作手游的角度来说明)

    简称AB.

        2)对象池的概念。

        3) GameObject:就是资源,直接可以new使用的类对象。简称obj。ab中存放的就是obj。

    二.加载

          何谓加载,一开始的时候资源全部下载好了,都是二进制的文件,即ab),是不能直接拿来用的。所以,需要你把这个ab中的资源全部抽出来,拿来使用。

        1.资源分类

          正常游戏,资源是很多的,尤其是做游戏。所以,你不可能一开始就把全部加载出来吧。

            弊端 a:内存撑爆,很影响游戏中的体验。

                b:一开始进入游戏时太卡,卡太久,很影响体验。

         所以,一般游戏初始化的时候,我们只会加载部分公共,核心,必须要加载的资源。当然啦,这个资源是在游戏登录之前进度条中加载的。很常见的吧。

         同理,在不同的模块根据所需,加载所需的资源。

         综上:资源分类大致 根据使用频度分类,使用模块分类。(还有资源的类型分类,如音频,MP4等)

     

        2.详解

          1)读取配置文件

            因为很多的资源,很多的资源存在各个依赖关系(重用,共用之类的),需要提前预知。Unity打包资源之后,会自动生成StreamingAssets的清单,里面包含所有资源,并且含有各个资源之间的依赖关系。将该清单中的关系保存到mDicAsset中。

          

           2)读取前的优化措施

             CRC加密:  首先,资源获取肯定是需要通过key,这个key肯定是字符串类型的路径,因为路径一般都比较冗长。

    所以可以通过CRC加密将字符串的路径转为int型。(起到加密和优化作用)

     

          3)正式开始读取资源

            已知有ab,ab中存放了obj,ab是我们已有的。 ab又不是我们直接可以使用的,我们可以直接使用的的是obj; 我们不能每次都直接加载ab或obj,

    所以最好是ab和obj都有缓存处理。

            因为我们的目的是使用obj,所以我们先加载obj的缓存。如果obj的缓存没有,我们再加载ab的缓存。如果

    没有obj的缓存,则加载ab的缓存,从中抽取出obj。如果又没有ab的缓存,则重新加载ab,将该ab缓存起来,抽取obj,缓存obj。

             LoadObj

            a.读取obj缓存资源

              I. 读取缓存mDicAsset,存在该资源的情况,引用计数增加,如果是从未引用过的资源,还需要在 mNoReferenceAssetMapList中移除;

              II.内存清理验证
                  如果缓存中没有该资源的情况则需要计算当前使用内存,如果内存大于450M(总内存大于1G,这个是举例,具体数值多少视运行环境,手机,pc等而定),清空缓存中一半(自定义)的内存。

               III.增加编译器模式下读取方法。(obj缓存资源没读到)

               为了便于开发,因为一开始我不可能每上传好一个资源,都打包一次(将资源打包成二进制)再加载,肯定不会这么做。所以在测试环境中指明一个可直接读取的obj的方法。即增加编译器模式开发的 方法.

     

            b.读取ab缓存资源

              I.通过mAssetItemDic找到这个资源对应的AssetItem对象,看他在哪个ab中,返回对应的ResourceItem。并判断该item 中ab是否已经load,已经有则返回。

              II.没有读到。调用LoadAssetBunle(path)方法 

               mAssetBundleItemDic缓存中读取,如果存在,则AssetBundleItem的refCount增加,并返回。如果不存在,则通过AssetBundle.LoadFromFile(引擎提供的加载ab的方法)。得到ab,并返回。

               每次AssetBundleItem为null时,需要new(但是这边我们做一个对象池的处理,不能每次都new),使用ClassObjectPool获取类对象。(不用new,在对象池中获取,由ObjectManager管理,ClassObjectPool为类对象池)

               III.加载依赖关系。

               我们如果加载一个ab的时候,他存在依赖关系,我们还需要之后加载该ab存在的依赖关系的ab。这是必须要做的,也是最麻烦的。(这边不好讲,太复杂,又太简单,简而言之了...)

               IV.获取到想要的ab之后,抽出需要的obj,并缓存到mDicAsset中。

            

          c.关于对象池的使用

            ObjectManager,对象管理器,类对象池中的实例生成,一般在切换场景,加载进度条之类的时候生成,这样,在load时候,不会有频繁的new。

            ClassObjectPool,类管理器。  

             

    三.释放

                1.为何要释放

              因为内存的问题,如果你不主动释放,他会被动,自动释放。被动,自动释放都是未知的,不能再关键时刻

    出现释放,因为释放的时候会影响帧率,影响游戏体验。所以一般我们最好保证内存不会自动释放,故,我们需要做主动释放。虽然C#有自动

    垃圾回收机制。但是这仅仅是对于托管资源(就是可以自动释放的)的,非托管资源.Net是不会自动释放的。

        2.释放的时机

              一般是切换场景时候释放,或者说若干模块功能结束后需要释放。

        3.释放哪些

              a.清理的时候,只能清理mNoReferenceAssetMapList中的数据,很明显,就是清理掉所有没有被引用的资源。

              b.释放crc这个资源对应的对象池。

              c.释放所占ab引用

                    卸载AssetBundleItem,需要item.assetBundle.Unload(false)

                    item.assetbundle = null

              d.注意非实例化出来的不能destroy,item.obj = null

                   

  • 相关阅读:
    MySQL数据库分区修改【原创】
    浅谈测试rhel7新功能时的感受及遇到的问题【转载】
    htop安装步骤【原创】
    Shell脚本,自动化发布tomcat项目【转】
    shell编程之服务脚本编写,文件锁以及信号捕获
    如何清除jboss缓存
    device-mapper: multipath: Failing path recovery【转载】
    ajax 设置Access-Control-Allow-Origin实现跨域访问
    HTML5中Access-Control-Allow-Origin解决跨域问题
    深入理解JavaScript系列(结局篇)
  • 原文地址:https://www.cnblogs.com/u3ddjw/p/9120430.html
Copyright © 2011-2022 走看看