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
加油,你很棒~