Unity 打包与加载AssetBundle加载对应的依赖

一、前言

加载AssetBundle的时候,如果AssetBundle依赖了另一个AssetBundle,则需要加载依赖的这个AssetBundle。本文我将演示一下具体过程。

二、打AssetBundle

如下,有一个球体Sphere预设,它对应的AssetBundle设置为test

在这里插入图片描述


Sphere依赖了材质球Material,材质球的AssetBundle设置为test2

我们在Editor中写个打包AssetBundle工具。

using UnityEngine;
using UnityEditor;

public class BuildAB
{
    [MenuItem("Tools/BuildAB")]
    public static void StartBuild()
    {
    	//打包AssetBundle,输出目录Application.streamingAssetsPath
        BuildPipeline.BuildAssetBundles(Application.streamingAssetsPath, 	
        								BuildAssetBundleOptions.ChunkBasedCompression, 
        								BuildTarget.StandaloneWindows);
    }
}

打出来的AssetBundle文件如下

在这里插入图片描述


我们可以看到,除了testtest2,还生成了一个StreamingAssets,这个StreamingAssets里面就记录了各个AssetBundle的依赖关系,我们可以打开StreamingAssets.manifest看看具体信息

ManifestFileVersion: 0
CRC: 4101034694
AssetBundleManifest:
  AssetBundleInfos:
    Info_0:
      Name: test
      Dependencies:
        Dependency_0: test2
    Info_1:
      Name: test2
      Dependencies: {}

可以看到test依赖了test2

三、编写加载AssetBundle管理器

为了方便管理加载,我们封装一个加载AssetBundle的管理器,代码中注释我写得比较清楚,这里不啰嗦了。

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

public class AssetBundleLoaderMgr
{
    /// <summary>
    /// 初始化,加载AssetBundleManifest,方便后面查找依赖
    /// </summary>
    public void Init()
    {
        string streamingAssetsAbPath = Path.Combine(Application.streamingAssetsPath, "StreamingAssets");
        AssetBundle streamingAssetsAb = AssetBundle.LoadFromFile(streamingAssetsAbPath);
        m_manifest = streamingAssetsAb.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
    }

    /// <summary>
    /// 加载AssetBundle
    /// </summary>
    /// <param name="abName">AssetBundle名称</param>
    /// <returns></returns>
    public AssetBundle LoadAssetBundle(string abName)
    {
        AssetBundle ab = null;
        if (!m_abDic.ContainsKey(abName))
        {
            string abResPath = Path.Combine(Application.streamingAssetsPath, abName);
            ab = AssetBundle.LoadFromFile(abResPath);
            m_abDic[abName] = ab;
        }
        else
        {
            ab = m_abDic[abName];
        }

        //加载依赖
        string[] dependences = m_manifest.GetAllDependencies(abName);
        int dependenceLen = dependences.Length;
        if (dependenceLen > 0)
        {
            for (int i = 0; i < dependenceLen; i++)
            {
                string dependenceAbName = dependences[i];
                if (!m_abDic.ContainsKey(dependenceAbName))
                {
                    AssetBundle dependenceAb = LoadAssetBundle(dependenceAbName);
                    m_abDic[dependenceAbName] = dependenceAb;
                }
            }
        }

        return ab;
    }

    /// <summary>
    /// 从AssetBundle中加载Asset
    /// </summary>
    /// <typeparam name="T">类型</typeparam>
    /// <param name="abName">AssetBundle名</param>
    /// <param name="assetName">Asset名</param>
    /// <returns></returns>
    public T LoadAsset<T>(string abName, string assetName) where T : Object
    {
        AssetBundle ab = LoadAssetBundle(abName);
        T t = ab.LoadAsset<T>(assetName);
        return t;
    }

    /// <summary>
    /// 缓存加载的AssetBundle,防止多次加载
    /// </summary>
    private Dictionary<string, AssetBundle> m_abDic = new Dictionary<string, AssetBundle>();

    /// <summary>
    /// 它保存了各个AssetBundle的依赖信息
    /// </summary>
    private AssetBundleManifest m_manifest;

    /// <summary>
    /// 单例
    /// </summary>
    private static AssetBundleLoaderMgr s_instance;
    public static AssetBundleLoaderMgr instance
    {
        get
        {
            if (null == s_instance)
                s_instance = new AssetBundleLoaderMgr();
            return s_instance;
        }
    }
}

四、运行测试

编写一个测试脚本,代码如下

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

public class Main : MonoBehaviour
{
    void Awake()
    {
        //初始化
        AssetBundleLoaderMgr.instance.Init();
    }

    void Start()
    {
        //从test中加载Sphere预设
        GameObject prefab = AssetBundleLoaderMgr.instance.LoadAsset<GameObject>("test", "Sphere");
        //实例化预设
        Instantiate(prefab);
    }
}

运行效果,可以看到球体和依赖的材质都正常加载了。

在这里插入图片描述

五、如果不加载依赖

如果我们把加载依赖的代码注释掉,不加载依赖,如下

在这里插入图片描述


现在我们再运行测试下,可以看到Sphere球体的材质球丢失了。

在这里插入图片描述


如果不想额外去加载Sphere球体的依赖,我们可以将材质球的AssetBundle设置为None,这样打出来的test就会将材质球一并打进去。

在这里插入图片描述


由于test包含了材质球的资源,所以文件比之前的大了一些。

在这里插入图片描述


这个时候,我们查看StreamingAssets.manifest,可以看到test已经不依赖其他的AssetBundle

ManifestFileVersion: 0
CRC: 153515353
AssetBundleManifest:
  AssetBundleInfos:
    Info_0:
      Name: test
      Dependencies: {}

此时,直接加载test,可正常加载Sphere球体。

在这里插入图片描述


好了,如果你你有什么疑问,可以在评论区留言。

相关文章

这篇文章将为大家详细讲解有关Unity3D中如何通过Animator动画...
这篇文章主要介绍了Unity3D如何播放游戏视频,具有一定借鉴价...
这篇文章给大家分享的是有关Unity3D各平台路径是什么的内容。...
小编给大家分享一下Unity3D如何实现移动平台上的角色阴影,希...
如何解析基于Unity3D的平坦四叉树地形与Virtual Texture的分...
这篇文章主要介绍Unity3D如何实现动态分辨率降低渲染开销,文...