动态加载----AssetBundleBrower

25 阅读1分钟

一、AssetBundle的管理类:

public class AssetBundleLoaderMgr
{
    /// <summary>
    /// 初始化,加载AssetBundleManifest,方便后面查找依赖
    /// </summary>
    public void Init()
    {
        string streamingAssetsAbPath = Path.Combine(Application.streamingAssetsPath, "StandaloneWindows");
        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];
        }

        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;
        }
    }
}

二、AssetBundle调用类:该脚本需要挂载在场景中的某个物体上,且需要输入标签名和预制体名。


public class LoadAb : MonoBehaviour
{
    [Header("标签名:")]
    public string assetBundle;
    [Header("预制体名:")]
    public string prefabName;
    void Awake()
    {
        //初始化
        AssetBundleLoaderMgr.instance.Init();
    }

    void LoadAsset()
    {
        //加载预设
        GameObject prefab = AssetBundleLoaderMgr.instance.LoadAsset<GameObject>(assetBundle, prefabName);
        //实例化预设
        Instantiate(prefab);
    }
    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.S))
        {
            LoadAsset();
        }
    }
}

三、资源复用

实际项目中会有多个预制体重复的部分,单独压缩浪费资源,所以需要将共同部分作为一个AssetBundle进行压缩。这样其它不同的部分就会对共同部分产生依赖。在做动态加载时,需要把依赖加载上,防止资源丢失。假设依赖资源是res。

为加载完整,需要在AssetBundleLoaderMgr脚本中加上加载依赖的代码。

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;
    }