1.本地異步
1 IEnumerator LoadFromMemoryAsync(string path) 2 3 { 4 5 AssetBundleCreateRequest createRequest = AssetBundle.LoadFromMemoryAsync(File.ReadAllBytes(path)); 6 7 yield return createRequest; 8 9 AssetBundle bundle = createRequest.assetBundle; 10 11 var prefab = bundle.LoadAsset<GameObject>("MyObject"); 12 Instantiate(prefab); 13 14 }
2.本地同步(同步會造成主線程的卡頓,造成游戲畫面的不流暢)
1 public class LoadFromFileExample extends MonoBehaviour { 2 function Start() { 3 var myLoadedAssetBundle = AssetBundle.LoadFromFile(Path.Combine(Application.streamingAssetsPath, "myassetBundle")); 4 if (myLoadedAssetBundle == null) { 5 Debug.Log("Failed to load AssetBundle!"); 6 return; 7 } 8 var prefab = myLoadedAssetBundle.LoadAsset<GameObject>("MyObject"); 9 Instantiate(prefab); 10 } 11 }
3.從web端下載並加載 (要引用UnityEngine.Networking命名空間)
IEnumerator IE_LoadAssetBundleByName(string bundleName) { while (!Caching.ready) { yield return null; } string fileType; #if UNITY_STANDALONE_WIN || UNITY_EDITOR fileType = "file://"; #elif UNITY_ANDROID && !UNITY_EDITOR fileType = "jar://"; #endif UnityWebRequest request = UnityEngine.Networking.UnityWebRequest.GetAssetBundle(fileType + assetBundlePath + "/" , 0); yield return request.SendWebRequest();//開始請求 while (!request.isDone) { Debug.Log("正在下載:" + request.downloadProgress.ToString()); yield return 1; } if (request.isDone) { Debug.Log("完成"); } if (request.isNetworkError || request.isHttpError) { Debug.Log("錯誤"); } else//完成 { Debug.Log("完成可用"); AssetBundle ab = DownloadHandlerAssetBundle.GetContent(request); //完成以后就能用了 if (ab == null) { yield break; } } request.Dispose(); }
加載好的AssetBundle使用以下這段代碼
1 T objectFromBundle = bundleObject.LoadAsset<T>(assetName);
T是要加載的資源類型。
決定如何加載資源時有幾個選項。我們有LoadAsset
,LoadAllAssets
和他們同行的異步LoadAssetAsync
和LoadAllAssetsAsync
分別。
這是如何同步從AssetBundles加載資源:
要加載單個GameObject:
1 GameObject gameObject = loadedAssetBundle.LoadAsset<GameObject>(assetName);
要加載所有資源:
1 Unity.Object[] objectArray = loadedAssetBundle.LoadAllAssets();
異步加載資源,在訪問資產之前,您需要等待此操作完成。
單個資源:
AssetBundleRequest request = loadedAssetBundleObject.LoadAssetAsync<GameObject>(assetName); yield return request; var loadedAsset = request.asset;
所有資源:
AssetBundleRequest request = loadedAssetBundle.LoadAllAssetsAsync(); yield return request; var loadedAssets = request.allAssets;
但是,為了節省空間,我們在打包AssetBundle包的時候經常把多個資源的依賴項單獨打包。比如說有兩個模型modelA和modelB,他們共同使用了matA的材質球,這個matA就是modelA和modelB的依賴項,如果我們只加載modelA或者modelB,那么這兩個模型的材質是丟失的。所以為了避免這個情況,我們要根據依賴文件來先找到依賴項並加載它(bundle包)。
加載依賴文件:
1 private void GetAssetBundleManifest(string path) 2 { 3 AssetBundle maniFestAb = AssetBundle.LoadFromFile(path + "/AssetBundles"); 4 if (maniFestAb == null) 5 { 6 Debug.Log("加載失敗"); 7 return; 8 } 9 AssetBundleManifest manifest = maniFestAb.LoadAsset<AssetBundleManifest>("AssetBundleManifest");//AssetBundleManifest基本固定的,不用改 10 11 string[] strArrAllAb = manifest.GetAllAssetBundles();//獲取所有包的包名(就是我們打包時候取的名字,連帶了路徑) 12 13 for (int i = 0; i < strArrAllAb.Length; i++) 14 { 15 //做你想做的事,推薦放到字典里,以后想加載的時候查找一次(廢話) 16 } 17 AssetBundle.UnloadAllAssetBundles(true);//如果用不到了記得卸載資源,把我們要的信息放個一個字典里就好,只加載一次(再次廢話)。 18 }
好了,我們雖然加載了資源,但是assetbundle包其實還留在內存中。這時候,為了節約性能,我們要把不用的資源刪除。
可以使用這個: AssetBundle.Unload(bool)
參數區別:
a. 參數是true的時候是完全卸載資源,包括了AB包(AssetBundle,一下都簡稱AB包,每次都打太麻煩了)和實例化的資源。就算是正在引用的資源也會被卸載,如果使用不當,會造成紋理丟失之類的情況。應該確保資源確實沒有哪里引用了,才調用AssetBundle.Unload(true);
b. 參數是false的時候會卸載所有沒有被引用的資源,這就造成了源AB包已經被卸載,實例化出來、並被人使用者的某資源就沒有了標記,再次加載這個物體的時候要重新加載ab包,加載你要的某資源,之前加載的某資源雖然沒有用了,但是還存在於游戲內存中,這樣下去就會越積越多,就炸了。
所以要調用一下 Resources.UnloadUnusedAssets(); 這個方法。另外,在游戲場景切換的時候,引擎也會自動的調用這個方法,把不存在引用的資源卸載。