Unity异步加载AssetBundle方案,4.x版本资源加载(5.x版本资源可以参考插件AssetBundleManager)

来源:互联网 发布:sql建立唯一索引 编辑:程序博客网 时间:2024/05/16 07:58

提升资源加载速度,不卡主线程的加载方式

using UnityEngine;using System.Collections;    public abstract class AssetBundleLoadOperation : IEnumerator    {        public object Current        {            get            {                return null;            }        }        public bool MoveNext()        {            return !IsDone();        }        public void Reset()        {        }        abstract public bool Update();        abstract public bool IsDone();    }    public class AssetBundleLoadLevelOperation : AssetBundleLoadOperation    {        protected string m_AssetBundleName;//资源名        protected string m_LevelName;//场景名        protected bool m_IsAdditive;        protected string m_DownloadingError;//下载错误信息        protected AsyncOperation m_Request;        #region//场景加载        public AssetBundleLoadLevelOperation(string assetbundleName, string levelName, bool isAdditive)        {            m_AssetBundleName = assetbundleName;            m_LevelName = levelName;            m_IsAdditive = isAdditive;        }        public override bool Update()        {            if (m_Request != null)                return false;            LoadedAssetBundle bundle = AssetBundleManager.GetLoadedAssetBundle(m_AssetBundleName, out m_DownloadingError);            if (bundle != null)            {                if (m_IsAdditive)                    m_Request = Application.LoadLevelAdditiveAsync(m_LevelName);                else                    m_Request = Application.LoadLevelAsync(m_LevelName);                return false;            }            else                return true;        }        public override bool IsDone()        {            // Return if meeting downloading error.            // m_DownloadingError might come from the dependency downloading.            if (m_Request == null && m_DownloadingError != null)            {                Debug.LogError(m_DownloadingError);                return true;            }            return m_Request != null && m_Request.isDone;        }    }        #endregion    public abstract class AssetBundleLoadAssetOperation : AssetBundleLoadOperation    {        public abstract T GetAsset<T>() where T : UnityEngine.Object;    }    public class AssetBundleLoadAssetOperationFull : AssetBundleLoadAssetOperation    {        protected string m_AssetBundleName;        protected string m_DownloadingError;        protected System.Type m_Type;        protected AssetBundleRequest m_Request = null;        public AssetBundleLoadAssetOperationFull(string bundleName, System.Type type)        {            m_AssetBundleName = bundleName;            m_Type = type;        }        public override T GetAsset<T>()        {            if (m_Request != null && m_Request.isDone)                return m_Request.asset as T;            else                return null;        }        // Returns true if more Update calls are required.        public override bool Update()        {            if (m_Request != null)                return false;            LoadedAssetBundle bundle = AssetBundleManager.GetLoadedAssetBundle(m_AssetBundleName, out m_DownloadingError);            if (bundle != null)            {                ///@TODO: When asset bundle download fails this throws an exception...                m_Request = bundle.m_AssetBundle.LoadAllAssetsAsync(m_Type);                return false;            }            else            {                return true;            }        }        public override bool IsDone()        {            // Return if meeting downloading error.            // m_DownloadingError might come from the dependency downloading.            if (m_Request == null && m_DownloadingError != null)            {                Debug.LogError(m_DownloadingError);                return true;            }            return m_Request != null && m_Request.isDone;        }    }

using System.Collections;using System.Collections.Generic;using UnityEngine;public class LoadedAssetBundle{    public AssetBundle m_AssetBundle;//assetbundle资源    public int m_ReferencedCount;//引用数量    public LoadedAssetBundle(AssetBundle assetBundle)    {        m_AssetBundle = assetBundle;        m_ReferencedCount = 1;    }}public class AssetBundleManager : MonoBehaviour {    static string m_BaseDownloadingURL = "";//加载地址(采用下载地址+文件名)    static Dictionary<string, LoadedAssetBundle> m_LoadedAssetBundles = new Dictionary<string, LoadedAssetBundle>();     //下载的资源    static Dictionary<string, WWW> m_DownloadingWWWs = new Dictionary<string, WWW>();                                    //下载列表    static Dictionary<string, string> m_DownloadingErrors = new Dictionary<string, string>();                            //下载错误信息    static List<AssetBundleLoadOperation> m_InProgressOperations = new List<AssetBundleLoadOperation>();                 //进度信息    //static Dictionary<string, string[]> m_Dependencies = new Dictionary<string, string[]>();                             //依赖信息    //加载地址    public static string BaseDownloadingURL    {        get { return m_BaseDownloadingURL; }        set { m_BaseDownloadingURL = value; }    }    //获取StreamingAssets路径    private static string GetStreamingAssetsPath()    {        if (Application.isEditor)            return "file://" + System.Environment.CurrentDirectory.Replace("\\", "/"); // Use the build output folder directly.        else if (Application.isWebPlayer)            return System.IO.Path.GetDirectoryName(Application.absoluteURL).Replace("\\", "/") + "/StreamingAssets";        else if (Application.isMobilePlatform || Application.isConsolePlatform)            return Application.streamingAssetsPath;        else // For standalone player.            return "file://" + Application.streamingAssetsPath;    }    //获取已加载资源    static public LoadedAssetBundle GetLoadedAssetBundle(string assetBundleName, out string error)    {        if (m_DownloadingErrors.TryGetValue(assetBundleName, out error))            return null;        LoadedAssetBundle bundle = null;        m_LoadedAssetBundles.TryGetValue(assetBundleName, out bundle);        if (bundle == null)            return null;        // No dependencies are recorded, only the bundle itself is required.        //string[] dependencies = null;        //if (!m_Dependencies.TryGetValue(assetBundleName, out dependencies))        //    return bundle;        // Make sure all dependencies are loaded        //foreach (var dependency in dependencies)        //{        //    if (m_DownloadingErrors.TryGetValue(assetBundleName, out error))        //        return bundle;        //    // Wait all the dependent assetBundles being loaded.        //    LoadedAssetBundle dependentBundle;        //    m_LoadedAssetBundles.TryGetValue(dependency, out dependentBundle);        //    if (dependentBundle == null)        //        return null;        //}        return bundle;    }    //释放资源    static protected void UnloadAssetBundleInternal(string assetBundleName)    {        string error;        LoadedAssetBundle bundle = GetLoadedAssetBundle(assetBundleName, out error);        if (bundle == null)            return;        if (--bundle.m_ReferencedCount == 0)        {            bundle.m_AssetBundle.Unload(false);            m_LoadedAssetBundles.Remove(assetBundleName);        }    }    //下载列表下载    void Update()    {        // Collect all the finished WWWs.        var keysToRemove = new List<string>();        foreach (var keyValue in m_DownloadingWWWs)        {            WWW download = keyValue.Value;            // If downloading fails.            if (download.error != null)            {                m_DownloadingErrors.Add(keyValue.Key, string.Format("Failed downloading bundle {0} from {1}: {2}", keyValue.Key, download.url, download.error));                keysToRemove.Add(keyValue.Key);                continue;            }            // If downloading succeeds.            if (download.isDone)            {                AssetBundle bundle = download.assetBundle;                if (bundle == null)                {                    m_DownloadingErrors.Add(keyValue.Key, string.Format("{0} is not a valid asset bundle.", keyValue.Key));                    keysToRemove.Add(keyValue.Key);                    continue;                }                //Debug.Log("Downloading " + keyValue.Key + " is done at frame " + Time.frameCount);                m_LoadedAssetBundles.Add(keyValue.Key, new LoadedAssetBundle(download.assetBundle));                keysToRemove.Add(keyValue.Key);            }        }        // Remove the finished WWWs.        foreach (var key in keysToRemove)        {            WWW download = m_DownloadingWWWs[key];            m_DownloadingWWWs.Remove(key);            download.Dispose();        }        // Update all in progress operations        for (int i = 0; i < m_InProgressOperations.Count; )        {            if (!m_InProgressOperations[i].Update())            {                m_InProgressOperations.RemoveAt(i);            }            else                i++;        }    }    //内部获取资源    static protected bool LoadAssetBundleInternal(string assetBundleName)    {        // Already loaded.        LoadedAssetBundle bundle = null;        m_LoadedAssetBundles.TryGetValue(assetBundleName, out bundle);        if (bundle != null)        {            bundle.m_ReferencedCount++;            return true;        }        // @TODO: Do we need to consider the referenced count of WWWs?        // In the demo, we never have duplicate WWWs as we wait LoadAssetAsync()/LoadLevelAsync() to be finished before calling another LoadAssetAsync()/LoadLevelAsync().        // But in the real case, users can call LoadAssetAsync()/LoadLevelAsync() several times then wait them to be finished which might have duplicate WWWs.        if (m_DownloadingWWWs.ContainsKey(assetBundleName))            return true;        WWW download = null;        string url = m_BaseDownloadingURL + assetBundleName;//基础路径加上文件名        download = new WWW(url);        m_DownloadingWWWs.Add(assetBundleName, download);        return false;    }    // Load AssetBundle and its dependencies.加载资源    static protected void LoadAssetBundle(string assetBundleName)    {        // Check if the assetBundle has already been processed.        bool isAlreadyProcessed = LoadAssetBundleInternal(assetBundleName);    }    // Load asset from the given assetBundle.异步加载资源    static public AssetBundleLoadAssetOperation LoadAssetAsync(string assetBundleName, System.Type type)    {        AssetBundleLoadAssetOperation operation = null;        {            LoadAssetBundle(assetBundleName);            operation = new AssetBundleLoadAssetOperationFull(assetBundleName, type);            m_InProgressOperations.Add(operation);        }        return operation;    }    #region//单例    // 定义一个静态变量来保存类的实例          private static AssetBundleManager instance;          // 定义一个标识确保线程同步          private static readonly object locker = new object();          // 定义私有构造函数,使外界不能创建该类实例          private AssetBundleManager()          {          }          /// <summary>          /// 定义公有方法提供一个全局访问点,同时你也可以定义公有属性来提供全局访问点          /// </summary>          /// <returns></returns>          public static AssetBundleManager Instance()          {              // 当第一个线程运行到这里时,此时会对locker对象 "加锁",              // 当第二个线程运行该方法时,首先检测到locker对象为"加锁"状态,该线程就会挂起等待第一个线程解锁              // lock语句运行完之后(即线程运行完之后)会对该对象"解锁"              lock (locker)              {                  // 如果类的实例不存在则创建,否则直接返回                  if (instance == null)                  {                    GameObject tGO = new GameObject("AssetBundleManager");                    tGO.AddComponent<AssetBundleManager>();                    instance = tGO.GetComponent<AssetBundleManager>();                    instance = new AssetBundleManager();                    Debug.Log("@@ Creat AssetBundleManager");                }              }            return instance;          }      #endregion}

加载案例

 void Start()    {        //异步加载资源+        AssetBundleManager.Instance();        AssetBundleManager.BaseDownloadingURL = PathManager.Instance().GetPath() + "101/New Folder/";        Debug.Log(AssetBundleManager.BaseDownloadingURL);        StartCoroutine(InstantiateGameObjectAsync("Cube.u3d"));            }    protected IEnumerator InstantiateGameObjectAsync(string assetBundleName)    {        // This is simply to get the elapsed time for this phase of AssetLoading.        float startTime = Time.realtimeSinceStartup;        // Load asset from assetBundle.        AssetBundleLoadAssetOperation request = AssetBundleManager.LoadAssetAsync(assetBundleName, typeof(GameObject));        if (request == null)        {            Debug.Log("request null");            yield break; }        yield return StartCoroutine(request);        // Get the asset.        var prefab = request.GetAsset<GameObject>();        if (prefab != null)            GameObject.Instantiate(prefab);        // Calculate and display the elapsed time.        float elapsedTime = Time.realtimeSinceStartup - startTime;        Debug.Log((prefab == null ? " was not" : " was") + " loaded successfully in " + elapsedTime + " seconds");    }




阅读全文
1 0