AssetsBundle资源包的打包和加载

如何打Assetsbundle资源包呢

这样

using UnityEditor;
using UnityEngine;

public class BuildAssetBundle
{
    /// <summary>
    /// 点击后,所有设置了AssetBundle名称的资源会被 分单个打包出来
    /// </summary>
    [MenuItem("AssetBundle/Build (Single)")]
    static void Build_AssetBundle()
    {
        BuildPipeline.BuildAssetBundles(Application.dataPath + "/Test_AssetBundle", BuildAssetBundleOptions.None, BuildTarget.StandaloneWindows);
        //如果你的ab包是给anidrod用的那就用下面这句
        //BuildPipeline.BuildAssetBundles(Application.dataPath + "/StreamingAssets", BuildAssetBundleOptions.None, BuildTarget.Android);
        //刷新
        AssetDatabase.Refresh();
    }

    /// <summary>
    /// 选择的资源合在一起被打包出来
    /// </summary>
    [MenuItem("AssetBundle/Build (Collection)")]
    static void Build_AssetBundle_Collection()
    {
        AssetBundleBuild[] buildMap = new AssetBundleBuild[1];
        //打包出来的资源包名字
        buildMap[0].assetBundleName = "enemybundle";

        //在Project视图中,选择要打包的对象  
        Object[] selects = Selection.GetFiltered(typeof(Object), SelectionMode.DeepAssets);
        string[] enemyAsset = new string[selects.Length];
        for (int i = 0; i < selects.Length; i++)
        {
            //获得选择 对象的路径
            enemyAsset[i] = AssetDatabase.GetAssetPath(selects[i]);
        }
        buildMap[0].assetNames = enemyAsset;

        BuildPipeline.BuildAssetBundles(Application.dataPath + "/Test_AssetBundle", buildMap, BuildAssetBundleOptions.None, BuildTarget.StandaloneWindows);
        //打Anidrod包
        //BuildPipeline.BuildAssetBundles(Application.dataPath+ "StreamingAssets", buildMap, BuildAssetBundleOptions.None, BuildTarget.Android);
        //刷新
        AssetDatabase.Refresh();
    }
}

使用代码前记得在assets文件夹下创建文件夹“Test_AssetBundle”,为打包提供路径

那么如何去使用assetsbundle资源包呢

这样

public GameObject _Canvas;//定义物体

 IEnumerator GetModel(int num, string path, int sum)
    {
        string endPath = @"file://" + Application.dataPath + "/Test_AssetBundle/interface01";
        //anidrod平台加载streamingAssets文件夹下的ab包资源用下面这句
        //string endPath = Application.streamingAssetsPath + "/interface02";
        //Android平台加载/storage/emulated/0/(SD卡)下的资源用这种格式
        //string endPath= "file://" + path
        Debug.Log(endPath);
        WWW www = new WWW(endPath);//加载
        yield return www;
        AssetBundle bundle = www.assetBundle;
        //资源加载 
        //加载的是打包到资源包里面,每个资源的名字
        Instantiate(bundle.LoadAsset("Panel1.prefab"),_Canvas.transform);
        //Instantiate(bundle.LoadAsset("Sphere.prefab"));
        //Instantiate(bundle.LoadAsset("Capsule.prefab"));

        //资源加载完毕后记得Unload,不然再次加载资源的时候无法加载
        yield return new WaitForSeconds(6);
        bundle.Unload(false);
        //GameObject Obj = (GameObject)Instantiate(bundle.mainAsset);
        //Obj.transform.SetParent(this.transform);
    }

解释一下,因为我加载的是一个panel,是个UI,需要放在canvas下,所以在这里呢,

Instantiate(bundle.LoadAsset("Panel1.prefab"),_Canvas.transform);

我直接在加载时就把指定资源"Panel1.prefab"给了"_Canvas"作为子物体。

怎么卸载资源

在项目中你可能只是加载一遍就不再加载了,也可能你要用到多个不同的资源,需要加载这个再去加载那个,重复加载,这个时候如果不及时的对bundle资源进行卸载,你的设备就会越来越卡顿,程序崩溃,软件闪退。

AssetBundle的卸载(抄来的)

如果说AssetBundle真的有什么容易出问题的地方,那恐怕就是卸载了。

在这里只说最常用的这个卸载方法吧:

public void Unload(bool unloadAllLoadedObjects);

一个被加载过的AssetBundle可以通过调用Unload来卸载这个Bundle下所有的Asset。但是调用这个函数时传入的参数对卸载结果影响甚大。

Unity官方对这个函数的讲解非常详细,配图也非常直观,因此我只是简单总结一下。

相同点:

无论传入参数为 true 或是 false,调用Unload都可以Destroy当前AssetBundle对象,释放之前从AssetBundle文件中的Header部分所获取的信息。当然,被释放的AssetBundle对象无法再使用诸如LoadAsset、LoadAllAssets等函数加载资源。

不同点:

unloadAllLoadedObjects == true:

不仅Destroy了AssetBundle这个对象,而且这个AssetBundle下包含的所有对象,只要实例化了,有一个算一个,统统释放掉。

感觉就像

foreach(Object asset in assets)

if(asset != null)

delete asset;

asset = null;

比如你通过ab.LoadAsset(apple)后,将apple设置给go_0的一个Renderer,如果这时候ab.Unload(true),那go_0就傻了,咋回事儿啊,图咋没了呢?WTF啊。

它的好处是:不会有重复资源问题的情况发生,每次都处理的干干净净。

unloadAllLoadedObjects == false:

仅仅Destroy了AssetBundle这个对象,但是并没有释放这个AssetBundle下的任何Asset,因此如果有对象引用了这些Asset,也不会有问题。

它的风险(代价)是:下次再Load这个AssetBundle,并且通过这个AssetBundle重新读取了这个Asset,会在内存中重新创建一份,这样如果之前的Asset没有被释放,那么现在内存中就有两份Asset了。

这种情况如果频繁发生,便意味着内存中有很多资源将“不受控制”,容易引发内存占用过高的问题,而释放这种不受控的资源,仅有两种方式:

1、当没有对象引用到这些不受控资源时,每次调用Resources.UnloadUnusedAssets,回收之。

2、加载场景时,如果加载模式没有设置为LoadSceneMode.Additive,则会自动调用Resources.UnloadUnusedAssets。

好了,兄弟资源卸载学会了吧。
没有的话可以到这看看更详细的分析
http://blog.sina.com.cn/s/blog_c3e21e750102yfng.html
加油,你很棒~

posted @ 2022-06-22 18:06  哒哒哒~~~  阅读(300)  评论(0编辑  收藏  举报