AssetBundle 加载、使用以及卸载

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是要加载的资源类型。

决定如何加载资源时有几个选项。我们有LoadAssetLoadAllAssets和他们同行的异步LoadAssetAsyncLoadAllAssetsAsync分别。

这是如何同步从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(); 这个方法。另外,在游戏场景切换的时候,引擎也会自动的调用这个方法,把不存在引用的资源卸载。

 

posted on 2019-05-09 12:15  炼金师  阅读(2590)  评论(0编辑  收藏  举报

导航