AssetBundle的使用

AssetBundle是一种资源管理机制

游戏更新的方式:

小版本更新:资源更新(图片、音频、预制体等)和配置文件更新

大版本更新:更新的是活动、新的玩法、系统模块 等;主要用于更新代码,也可以用于更新资源

资源打包机制:

一些文件:音频、图片、配置文件或者Lua文件想要加载到已经安装的安装包里,只能通过 资源打包机制 进行加载

加载过程:将所有unity可以识别的资源类型 都理解为AssetBundle(资源包),加载之后如何使用,是逻辑层面的内容

注意:

AssetBundle 可以包含资源的全部依赖关系;预制体依赖材质球等

可压缩 跨文件 (预制体、二进制文件、图片等)

AssetBundle 是为了做资源更新存在的

使用流程:

打包

using UnityEditor;
using UnityEngine;

public class ABEditor : Editor
{
    [MenuItem("AssetBundle/Build(Single)")]
    static void BuildSingle()
    {
        BuildPipeline.BuildAssetBundles(
            Application.streamingAssetsPath + "/",
            BuildAssetBundleOptions.None,
            BuildTarget.StandaloneWindows
        );
        AssetDatabase.Refresh();
    }

    [MenuItem("AssetBundle/Build(Collection)")]
    static void BuildAll()
    {
        // 对当前选中的这些物体 进行整体打包
        AssetBundleBuild[] builds = new AssetBundleBuild[1];
        builds[0].assetBundleName = "allBundles";
        Object[] selects = Selection.GetFiltered(typeof(Object), SelectionMode.DeepAssets /*强制包含 整个资源 及其 对应的依赖资源*/);
        string[] allAssetPaths = new string[selects.Length];
        for (int i = 0; i < allAssetPaths.Length; i++)
        {
            allAssetPaths[i] = AssetDatabase.GetAssetPath(selects[i]);
        }

        builds[0].assetNames = allAssetPaths;

        BuildPipeline.BuildAssetBundles(
            Application.streamingAssetsPath + "/",
            builds,
            BuildAssetBundleOptions.None,
            BuildTarget.StandaloneWindows
        );
        AssetDatabase.Refresh();
    }
}

BuildAssetBundleOptions

1. None:构建AssetBundle没有任何特殊的选项;

2. UncompressedAssetBundle:不进行数据压缩。没有压缩/解压的过程,AssetBundle的发布和加载会更快,但是AssetBundle也会更大,导致下载速度变慢;

3. CollectDependencies:包括所有依赖关系的资源 (AssetBundle中所有类型的hash);

4. DisableWriteTypeTree:在AssetBundle中不包含类型信息(TypeTree)。Web平台上不能使用该选项;

5. DeterministicAssetBundle:使每个Object具有唯一不变的hash ID,使用ID可避免资源

改名、移动位置等导致重新导出。 可用于增量式发布AssetBundle;

6. ForceRebuildAssetBundle:强制重新Build所有的AssetBundle;

7. IgnoreTypeTreeChanges:忽略TypeTree的变化,不能与DisbaleTypeTree同时使用。

8. AppendHashToAssetBundleName:附加Hash到AssetBundle名称中。

9. ChunkBasedCompression:使用LZ4压缩算法来Build AssetBundle。默认LZMA压 缩。

10. StrictMode:如果发布过程中有任何错误报告就不允许发布成功。

11. DryRunBuild:获得打包一个AssetBundle的AssetBundleManifest,AssetBundleManifest对象包含有效AssetBundle依赖性和散列。但是不实际创建AssetBundle。

12. DisableLoadAssetByFileName:不允许AB包通过文件名加载资源。

13. DisableLoadAssetByFileNameWithExtension:禁用通过使用扩展名加载AssetBundle。

LZ4:相对 LZMA 压缩比更低,所以打包后 包体 会更大点,运行时 解压更快 且没有额外的内存消耗

LZMA:相对LZ4压缩更高,所以包体更小,运行时 解压速度 慢 且 有额外的内存消耗

加载

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class LoadABTest : MonoBehaviour
{
    private void OnGUI()
    {
        if (GUILayout.Button("单独加载Cube"))
        {
            StartCoroutine(LoadAssetBundleSingle("cube"));
        }

        if (GUILayout.Button("整体加载"))
        {
            StartCoroutine(LoadAssetBundleAll());
        }

        if (GUILayout.Button("LoadByCache"))
        {
            StartCoroutine(LoadAssetBundleByCacheOrDownload("sphere"));
        }
    }

    IEnumerator LoadAssetBundleSingle(string assetName)
    {
        WWW www = new WWW(Application.streamingAssetsPath + "/" + assetName);
        yield return www;
        string[] assetBundles = www.assetBundle.GetAllAssetNames();
        Instantiate(www.assetBundle.LoadAsset(assetBundles[0]));
        // www.assetBundle.Unload(true);
    }
    
    IEnumerator LoadAssetBundleAll()
    {
        WWW www = new WWW(Application.streamingAssetsPath + "/allbundles");
        yield return www;
        string[] assetBundles = www.assetBundle.GetAllAssetNames();
        foreach (string asset in assetBundles)
        {
            Instantiate(www.assetBundle.LoadAsset(asset));
        }
    }

    IEnumerator LoadAssetBundleByCacheOrDownload(string name)
    {
        Caching.ClearCache();
        WWW www = WWW.LoadFromCacheOrDownload(Application.streamingAssetsPath + "/" + name, 2);
        yield return www;
        string[] assetBundles = www.assetBundle.GetAllAssetNames();
        Instantiate(www.assetBundle.LoadAsset(assetBundles[0]));
    }
}

新版加载方式

using System;
using System.Collections;
using UnityEngine;
using UnityEngine.Networking;
using Object = System.Object;

public class LoadAssetBundle : MonoBehaviour
{
    private void OnGUI()
    {
        if (GUILayout.Button("加载Cube"))
        {
            StartCoroutine(LoadAssetBundleSingle("cube"));
        }

        if (GUILayout.Button("加载整体"))
        {
            StartCoroutine(LoadAssetBundleAll());
        }
    }

    IEnumerator LoadAssetBundleSingle(string assetName)
    {
        UnityWebRequest request = UnityWebRequestAssetBundle.GetAssetBundle("http://cdn.shongfei.top/test/cube");
        yield return request.SendWebRequest();
        if (request.result == UnityWebRequest.Result.ConnectionError ||
            request.result == UnityWebRequest.Result.ProtocolError)
        {
            Debug.LogError(request.error);
        }

        print(request);
        AssetBundle ab = (request.downloadHandler as DownloadHandlerAssetBundle)?.assetBundle;
        print(ab);
        // AssetBundle bundle = AssetBundle.LoadFromFile();
        if (ab != null)
        {
            GameObject obj = ab.LoadAsset<GameObject>(assetName);
            Instantiate(obj);
        }
    }

    IEnumerator LoadAssetBundleAll()
    {
        AssetBundle bundle = AssetBundle.LoadFromFile(Application.streamingAssetsPath + "/allbundles");
        yield return bundle;
        Object[] bundles = bundle.LoadAllAssets();
        foreach (GameObject bun in bundles)
        {
            Instantiate(bun);
        }
    }
}

卸载

AssetBundle 下载的资源(不管是从网络上 or 本地文件中)存储 在内存的文件镜像区域中

当使用Load去加载的时候,将 文件镜像内存 区域中的信息加载到 缓存区域(和Resources.Load加载资源属于同一个区域)

通过实例化的方法克隆出对象,会加载到另一块内存(实际内存),也就是说可以在场景视图中看到的对象

如果实例化出来的对象,使用Destroy来卸载释放

通过Resources.Load所加载的资源,需要通过Resources.UnLoadAssets和UnLoadUnsedAsset来卸载

AssetBundle.UnLoad卸载资源包:

  • false 卸载的是文件内存 镜像区域,不会影响之前加载的资源的使用
  • true 卸载的内存 镜像 和 通过Load加载的资源(缓存区)
上一篇
下一篇