欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Unity用户手册-AssetBundle

程序员文章站 2022-06-15 09:06:36
...

AssetBundle

什么是AssetBundle?

AssetBundle实际上是一个资源管理包。AssetBundle 包含了两个部分:数据头以及数据段。数据头内包含了 AssetBundle 的元数据信息,比如它的标识符、压缩类型、manifest 等等。这里的 manifest 是一个以 Object 名称作为键的查找表,用以指定 AssetBundle 中给定 Object 的位置。数据段内包含了序列化 Asset 生成的原始数据,内容会依据压缩算法变化。

AssetBundle 具有如下优点:

  • 可以按需加载和释放 Asset 。
  • 自带压缩算法,可以按需定制,减少包体容量。
  • 自带版本更新内容,可以进行增量更新。
  • 内部包含了对 Object 的引用关系。

 

第一种是在磁盘上的实际文件,就像一个容器,一个文件夹,可以包含其他文件(模型,纹理,预制,音频,甚至整个场景)。没有后缀名称的AssetBundle文件,这个文件是包含了所有的依赖关系的配置文件,加载AssetBundle就是加载的这个文件,有后缀名称的manifest文件,只是用来做本地依赖关系和增量打包的时候用的。

第二种是运行时加载的AssetBundle对象,包含添加到AssetBundle中的所有资产的路径映射,及资产的对象。

 

UnityWebRequestAssetBundle获取AssetBundle

public void LoadResource(string resName, string filePath)
    {
        StartCoroutine(LoadResourceCorotine(resName, filePath));
    }

    IEnumerator LoadResourceCorotine(string resName, string filePath)
    {
        AssetBundle ab = null;
         UnityWebRequest request = UnityWebRequestAssetBundle.GetAssetBundle(@"http://localhost/AssetBundles/" + filePath);
         yield return request.SendWebRequest();
         if (request.isNetworkError || request.isHttpError)
        {
            Debug.Log(request.error);
        }
        else
        {
            ab = DownloadHandlerAssetBundle.GetContent(request);
            //ab = (request.downloadHandler as DownloadHandlerAssetBundle).assetBundle;
        }
        if (ab == null)
        {
            yield break;
        }
        //同步加载
        //GameObject gameObject = ab.LoadAsset<GameObject>(resName);
        //异步加载
        AssetBundleRequest abRequest = ab.LoadAssetAsync<GameObject>("Cube");
        yield return abRequest;
        GameObject ob = abRequest.asset as GameObject;
        Instantiate(ob);
        // 卸载所有的资源
        ab.Unload(true);
    }

 

UnityWebRequest获取文本文件,并写入到固定目录

IEnumerator LoadResourceCorotine()
    {
        UnityWebRequest request = UnityWebRequest.Get(@"http://localhost/fish.lua.txt");
        yield return request.SendWebRequest();
        string str = request.downloadHandler.text;
        File.WriteAllText(@"D:\BaiduNetdiskDownload\xLua_unity\XluaProjects\XluaProjects\PlayerGamePackage\fish.lua.txt", str);
        UnityWebRequest request1 = UnityWebRequest.Get(@"http://localhost/fishDispose.lua.txt");
        yield return request1.SendWebRequest();
        string str1 = request1.downloadHandler.text;
        File.WriteAllText(@"D:\BaiduNetdiskDownload\xLua_unity\XluaProjects\XluaProjects\PlayerGamePackage\fishDispose.lua.txt", str1);
    }

Unity用户手册-AssetBundle

 

一、AssetBundle的加载

 

AssetBundle.LoadFromFile 从磁盘上的文件同步加载AssetBundle

AssetBundle.LoadFromFileAsync 从磁盘上的文件异步加载AssetBundle

函数支持任何压缩类型的包。在lzma压缩的情况下,数据将被解压缩到内存中。可以直接从磁盘读取未压缩和块压缩(chunkcompressed,也就是LZ4)的包。

 

AssetBundle.LoadFromMemory 从内存同步创建AssetBundle

AssetBundle.LoadFromMemoryAsync 从内存异步创建AssetBundle

使用此方法从字节数组创建AssetBundle。当您使用加密下载数据并需要从未加密的字节创建AssetBundle时,这非常有用。

 

AssetBundle.LoadFromStream 从托管流同步加载AssetBundle

AssetBundle.LoadFromStreamAsync 从托管流异步加载AssetBundle

函数支持任何压缩类型的包。在lzma压缩的情况下,数据将被解压缩到内存中。可以直接从磁盘读取未压缩和块压缩(chunkcompressed,也就是LZ4)的包。

在加载AssetBundle或捆绑包中的任何资产时,请勿释放Stream对象。它的寿命应该比AssetBundle长。这意味着在调用AssetBundle.Unload之后处理Stream对象。

 

LZ4算法是“基于块”的,因此当对象从一个LZ4压缩包加载时,仅用于该对象的相应块会被解压。

即使AssetBundle的其他块未解压缩,解压缩单个块允许使用包含的资产。

 

UnityWebRequestAssetBundle.GetAssetBundle 创建UnityWebRequest,优化用于通过HTTP GET下载Unity资产包

 

二、Asset的加载

AssetBundle.LoadAsset 从资源包中加载指定的资源

AssetBundle.LoadAssetAsync 从资源包中异步加载资源

 

AssetBundle.LoadAllAsset 加载当前资源包中所有的资源

AssetBundle.LoadAllAssetAsync 异步加载当前资源包中所有的资源

 

三、Asset的卸载

AssetBundle.Unload

卸载捆绑包中的所有资产,卸载释放与包内对象关联的所有内存。

AssetBundle.Unload(false) 仅仅销毁AssetBundle对象包含的资源,任何从此包中加载的实际对象保持不变。当然,也将无法从此AssetBundle包中加载任何其他对象。

AssetBundle.Unload(true) 销毁AssetBundle对象包含的资源,同时销毁从此包中加载的资源对象,即会释放AssetBundle.LoadAsset等加载的资源对象。如果场景中有游戏对象引用这些资源,则对它们的引用都会丢失。

 

Resources.UnloadAssets 释放指定的Asset

Resources.UnloadUnusedAssets 释放没有引用的Asset

 

AssetBundle的粒度

即每个AssetBundle包含多少资源

 

 

打包策略

 

  • 将公共依赖的资源打包到一个公共AssetBundle中,独立的资源打包到一个AssetBundle中
  • 将相同类型的资源(Shader、Atlas、Prefab、Material、Scene、动画、声音、特效等)打包成一个AssetBundle
  • 地图、Monster、Npc、角色、坐骑、神翼等根据配置进行打包
  • 根据资源间的引用关系,去除重复的资源

 

去除重复的资源

对于没有被指定打包的外部资源,如果多个ab包依赖了它,打包时该资源就会被多次打包进依赖它的ab包中,造成冗余。

解决方案:

建立了三个对应关系的字典:

Dictionary<string, Bundle> m_BundleDic = new Dictionary<string, Bundle>();

Dictionary<string, Asset> m_AssetDic = new Dictionary<string, Asset>();

Dictionary<string, string> m_AssetMapBundleDic = new Dictionary<string, string>();

m_BundleDic:维护了BundleName-Bundle对象对应关系的字典,其中Bundle对象中,维护了当前Bundle中所有的资源列表AssetList。

m_AssetDic:维护了AssetName-Asset对象对应关系的字典

m_AssetMapBundleDic:维护了AssetName-BundleName对应关系的字典

 

具体操作步骤:

1. 创建一个HashSet,确保所有的资源Asset在Bundle中是唯一的,不产生冗余。

1. 遍历m_BundleDic中每一个Bundle对象的AssetList;

2. 如果不在HashSet中,把Asset加入到HashSet中,否则,执行删除冗余操作;

3. 如果HashSet已经存在相同的Asset时,通过m_AssetMapBundleDic字典获得当前Asset对应的BundleName;

4. 如果当前Asset对应的BundleName在m_BundleDic中,表示多个ab包依赖了这个Asset,从对应的Bundle的AssetList中移除这个Asset。

5.如果当前Asset对应的BundleName不在m_BundleDic中,表示虽然多个ab包依赖了这个Asset,但是其中有一些并不需要打到ab包中,这时,需要把对应的Bundle从m_AssetMapBundleDic中移除。