Unity5.x版本AssetBundle加载研究
之前说了 “Unity5.x版本AssetBundle打包研究”,没看过的请先看一下:http://www.shihuanjue.com/?p=57
再来看本文,有一定的连接性。
先梳理一下思路:
要加载一个资源A,必须先去加载它的所有依赖资源
要知道这个资源A依赖了哪些资源,必须先去加载AssetBundleManifest
通过AssetBundleManifest对象的GetAllDependencies(A)方法,获取它依赖的所有资源。
依赖资源都加载了,就可以去真正加载资源A了。
注意点:
1.资源A加载完了后,要记得Unload(false),资源A的依赖资源要在 资源A加载完成后,才能Unload(false),否则无法正常加载资源A
2.不Unload的话也可以,那就自己做一个字典记录所有加载过的AssetBundle,还有它们的引用计数器。那样就可以先判断是否存在,然后再确定是否要去加载。
我下面的例子,采用1的方式。就是加载完了后就Unload的方式。
上代码
using UnityEngine; using System.Collections; using System.Collections.Generic; using System; public class AssetBundleLoaderMgr : Singleton<AssetBundleLoaderMgr> { public string m_assetPath = Application.streamingAssetsPath; string assetTail = ".unity3d"; #region LoadAssetBundle /// <summary> /// 加载目标资源 /// </summary> /// <param name="name"></param> /// <param name="callback"></param> public void LoadAssetBundle(string name, Action<UnityEngine.Object> callback) { name = name + assetTail;//eg:ui/panel.unity3d Action<List<AssetBundle>> action = (depenceAssetBundles) => { string realName = this.GetRuntimePlatform() + "/" + name;//eg:Windows/ui/panel.unity3d LoadResReturnWWW(realName, (www) => { int index = realName.LastIndexOf("/"); string assetName = realName.Substring(index + 1); assetName = assetName.Replace(assetTail, ""); AssetBundle assetBundle = www.assetBundle; UnityEngine.Object obj = assetBundle.LoadAsset(assetName);//LoadAsset(name),这个name没有后缀,eg:panel //卸载资源内存 assetBundle.Unload(false); for (int i = 0; i < depenceAssetBundles.Count; i++) { depenceAssetBundles[i].Unload(false); } //加载目标资源完成的回调 callback(obj); }); }; LoadDependenceAssets(name, action); } /// <summary> /// 加载目标资源的依赖资源 /// </summary> /// <param name="targetAssetName"></param> /// <param name="action"></param> private void LoadDependenceAssets(string targetAssetName, Action<List<AssetBundle>> action) { Debug.Log("要加载的目标资源:" + targetAssetName);//ui/panel.unity3d Action<AssetBundleManifest> dependenceAction = (manifest) => { List<AssetBundle> depenceAssetBundles = new List<AssetBundle>();//用来存放加载出来的依赖资源的AssetBundle string[] dependences = manifest.GetAllDependencies(targetAssetName); Debug.Log("依赖文件个数:" + dependences.Length); int length = dependences.Length; int finishedCount = 0; if (length == 0) { //没有依赖 action(depenceAssetBundles); } else { //有依赖,加载所有依赖资源 for (int i = 0; i < length; i++) { string dependenceAssetName = dependences[i]; dependenceAssetName = GetRuntimePlatform() + "/" + dependenceAssetName;//eg:Windows/altas/heroiconatlas.unity3d //加载,加到assetpool LoadResReturnWWW(dependenceAssetName, (www) => { int index = dependenceAssetName.LastIndexOf("/"); string assetName = dependenceAssetName.Substring(index + 1); assetName = assetName.Replace(assetTail, ""); AssetBundle assetBundle = www.assetBundle; UnityEngine.Object obj = assetBundle.LoadAsset(assetName); //assetBundle.Unload(false); depenceAssetBundles.Add(assetBundle); finishedCount++; if (finishedCount == length) { //依赖都加载完了 action(depenceAssetBundles); } }); } } }; LoadAssetBundleManifest(dependenceAction); } /// <summary> /// 加载AssetBundleManifest /// </summary> /// <param name="action"></param> private void LoadAssetBundleManifest(Action<AssetBundleManifest> action) { string manifestName = this.GetRuntimePlatform(); manifestName = manifestName + "/" + manifestName;//eg:Windows/Windows LoadResReturnWWW(manifestName, (www) => { AssetBundle assetBundle = www.assetBundle; UnityEngine.Object obj = assetBundle.LoadAsset("AssetBundleManifest"); assetBundle.Unload(false); AssetBundleManifest manif = obj as AssetBundleManifest; action(manif); }); } #endregion #region ExcuteLoader public void LoadResReturnWWW(string name, Action<WWW> callback) { string path = "file://" + this.m_assetPath + "/" + name; Debug.Log("加载:" + path); StartCoroutine(LoaderRes(path, callback)); } IEnumerator LoaderRes(string path, Action<WWW> callback) { WWW www = new WWW(path); yield return www; if (www.isDone) { callback(www); } } #endregion #region Util /// <summary> /// 平台对应文件夹 /// </summary> /// <returns></returns> private string GetRuntimePlatform() { string platform = ""; if (Application.platform == RuntimePlatform.WindowsPlayer || Application.platform == RuntimePlatform.WindowsEditor) { platform = "Windows"; } else if (Application.platform == RuntimePlatform.Android) { platform = "Android"; } else if (Application.platform == RuntimePlatform.IPhonePlayer) { platform = "IOS"; } else if (Application.platform == RuntimePlatform.OSXPlayer || Application.platform == RuntimePlatform.OSXEditor) { platform = "OSX"; } return platform; } } #endregion
测试一下咯
using UnityEngine; using System.Collections; using System.Collections.Generic; public class TestAssetBundleLoader : MonoBehaviour { Dictionary<string, GameObject> GameObjectPool = new Dictionary<string, GameObject>(); void Start() { //要加载的资源的队列 Queue<string> needLoadQueue = new Queue<string>(); needLoadQueue.Enqueue("ui/plane"); needLoadQueue.Enqueue("ui/cube"); needLoadQueue.Enqueue("ui/sphere"); Load(needLoadQueue); } void Load(Queue<string> needLoadQueue) { if (needLoadQueue.Count > 0) { string needLoadAssetName = needLoadQueue.Dequeue(); AssetBundleLoaderMgr.Instance.LoadAssetBundle(needLoadAssetName, (obj) => { GameObject go = GameObject.Instantiate(obj) as GameObject; int index = needLoadAssetName.LastIndexOf("/"); string assetName = needLoadAssetName.Substring(index + 1); //加载出来的GameObject放到GameObjectPool存储 GameObjectPool.Add(assetName, go); Load(needLoadQueue); }); } else { Debug.Log("all finished"); } } }
有图有真相
可能代码写的还有很多优化的地方 ,毕竟100个人有100种写法,思路才是最重要的。你说呢?
其实我想说的是,代码都在了,自己尝试一下吧!
- 本文固定链接: http://www.shihuanjue.com/?p=83
- 转载请注明: 乔 2015年09月10日 于 是幻觉 发表