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

                   

  • 相关阅读:
    HYSBZ 3813 奇数国
    HYSBZ 4419 发微博
    HYSBZ 1079 着色方案
    HYSBZ 3506 排序机械臂
    HYSBZ 3224 Tyvj 1728 普通平衡树
    Unity 3D,地形属性
    nginx 的naginx 种包含include关键字
    Redis 出现NOAUTH Authentication required解决方案
    mysql 8.0出现 Public Key Retrieval is not allowed
    修改jar包里的源码时候需要注意的问题
  • 原文地址:https://www.cnblogs.com/u3ddjw/p/9120430.html
Copyright © 2011-2022 走看看