牛骨文教育服务平台(让学习变的简单)
博文笔记

Unity之资源打包Assetbundle

创建时间:2014-10-20 投稿人: 浏览次数:2176

一、如何创建AssetBundle(后面简写为AB)

1.1 创建的方法(三种)

 BuildPipeline.BuildAssetBundle()
• 将Project文件夹中的任意个Assets打包成一个AB
• 一般适用于对单个大规模场景的细分


BuildPipeline.BuildStreamedSceneAssetBundle()
• 将一个或多个场景中的资源及其所有依赖打包成一个AB
• 一般适用于对单个或多个场景进行集中打包


BuildPipeline.BuildAssetBundleExplicitAssetNames()
• 将Project文件夹中的任意个Assets打包成一个AB
• 可以为该AB中的每个Asset命名

说明:第一种主要是用于打包场景中的资源,第二种主要用于打包整个场景,第三种不常用,主要使用前面两种方法即可

 

1.2 创建的示例

1.2.1 打包资源

头文件:

using UnityEngine;
using UnityEditor;

    //在Unity编辑器中添加菜单
    [MenuItem("Assets/Build AssetBundle From Selection")]
    static void ExportResourceRGB2()
    {
        // 打开保存面板,获得用户选择的路径
        string path = EditorUtility.SaveFilePanel("Save Resource", "", "New Resource", "assetbundle");

        if (path.Length != 0)
        {
            // 选择的要保存的对象
            Object[] selection = Selection.GetFiltered(typeof(Object), SelectionMode.DeepAssets);
            //打包
            BuildPipeline.BuildAssetBundle(Selection.activeObject, selection, path, BuildAssetBundleOptions.CollectDependencies | BuildAssetBundleOptions.CompleteAssets, BuildTarget.StandaloneWindows);
        }
    }
[MenuItem("Assets/Save Scene")]
	static void ExportScene()
	{
		// 打开保存面板,获得用户选择的路径
		string path = EditorUtility.SaveFilePanel("Save Resource", "", "test", "unity3d");
		
		if (path.Length != 0)
		{
			// 选择的要保存的对象
			Object[] selection = Selection.GetFiltered(typeof(Object), SelectionMode.DeepAssets);
			string[] scenes = {"Assets/Scenes/test.unity"};
			//打包
			BuildPipeline.BuildStreamedSceneAssetBundle(scenes,path,BuildTarget.WebPlayer);  
		}
	}


 

a、创建一个空的Prefab,命名Cube,然后创建一个Cube,将其拉到刚创建好的Prefab

b、新建一个脚本ExportAssetBundles.cs(代码来自官方文档),保存在Asset/Editor目录下并把上面的代码复制到该脚本上

c、这时我们将看到在菜单栏上Asset下面出现Build AssetBundle From Selection 和 Sade Scene(上面大部分的代码也是为了实现这个功能,这样就不用运行程序就可以执行代码打包资源)

d、选中预设Cube,运行Build AssetBundle From Selection。这时会弹出一个保存框,将其命名为cube.unity3d(路径保存在你需要的地方)

e、新建一个场景scene1.unity,上面放置几个模型,然后保存

f、选中该场景,在之前的ExportAssetBundles.cs脚本中添加打包场景的函数,运行Assets->Build Scene,保存为scene1.unity3d(同样保存你需要的地方)

 

1.2.2 参数设置

BuildAssetBundle

参数1:被选中的单个资源对象(打包单个的时候用这个参数)

参数2:被选中的资源对象数组(打包多个的时候用这个参数)

参数3:被打包资源所在的位置

参数4:AB的选项

     CompleteAssets  使每个Asset本身完备化(简单说就是连同对象的组件一起打包,比如transform、碰撞器、脚本组件等)

     CollectDependencies 包入每个Asset依赖的所有资源(简单说就是你的自己的工程资源,比如皮肤资源等)

     DeterministicAssetBundle  使每个Object具有唯一的、不变的Hash ID,便于后续查找

     UncompressedAssetBundle  不进行数据压缩

需要某个选项的时候就是用|来启用

参数5:.BuildAssetBundle要根据不同的平台单独打包,BuildTarget参数指定平台,如果不指定,默认的webplayer

 

1.2.3 注意事项

a、AssetBundle的保存后缀名可以是assetbundle或者unity3d

b、本地测试也就是要在真机上测试而且资源是放在本机上(不是通过服务器下载的话)的时候,最后将Assetbundle放在StreamingAssets文件夹下,如果没有就创建一个,因为移动平台下只能读取这个路径
c、默认情况下打的包只能在电脑上用,如果要在手机上用就要添加一个参数。
Android上:BuildPipeline.BuildAssetBundle (obj, null, targetPath, BuildAssetBundleOptions.CollectDependencies,BuildTarget.Android)
IOS上:BuildPipeline.BuildAssetBundle (obj, null, targetPath, BuildAssetBundleOptions.CollectDependencies,BuildTarget.iPhone)
另外,电脑上和手机上打出来的Assetbundle不能混用,不同平台只能用自己的,也就是不同的平台是通过参数5来设置

d、无论是模型资源还是UI资源,最好是先把他们放在Prefab中,然后在做成Assetbundle

e、关于资源打包的空间问题,如果是不同的模型的话分开打和一起打结果是一样的,但是如果是相同的模型,仅仅只是脚本不一样,模型身上的材质,贴图等是一样的就要一起打包,否则就会出现一份资源占用两个空间的情况,当然如果非要分开打但又要节约空间,就可以使用依赖关系来实现。

f、不同平台下StreamingAssets的路径是不同的,这里需要注意一下。

 	public static  string PathURL = 
	#if UNITY_ANDROID 
		"jar:file://" + Application.dataPath + "!/assets/"; 
	#elif UNITY_IPHONE 	
		Application.dataPath + "/Raw/"; 
	#elif UNITY_STANDALONE_WIN || UNITY_EDITOR 
		"file://" + Application.dataPath + "/StreamingAssets/"; 
	#else 	
		string.Empty; 
	#endif 


二、下载资源

2.1 方法

WWW bundle = new WWW(path);
WWW bundle = WWW.LoadFromCacheOrDownload(path,5);

2.2 区别

方法一:

通过一个路径进行下载(无论是服务器路径还是本地路径下载操作都一样)但是bundle只能保存在内存中,也就是退出游戏在进入还得重新下,很显然在游戏中我们不能经常使用这种方式。
方法二:

参数1:服务器或者本地下载地址
参数2:版本号
Unity会下载Assetbundle本地中,它的工作原理是先通过(版本号和下载地址)先在本地去找看有没有这个Assetbundle,如果有直接返回对象,如果没有的话,在根据这个下载地址重新从服务器或者本地下载。这里版本号起到了很重要的作用,举个例子,同一下载地址版本号为1的时候已经下载到本地,此时将版本号的参数改成2 那么它又会重新下载,如果还保持版本号为1那么它会从本地读取,因为本地已经有版本号为1的这个Assetbundle了。你不用担心你的资源本地下载过多,也不用自己手动删除他们,这一切的一切Unity会帮我们自动完成,它会自动删除掉下载后最不常用的Assetbundle ,如果下次需要使用的话只要提供下载地址和版本后它会重新下载。

三、创建AssertBundle对象

3.1 直接通过WWW.assetbundle属性来创建assetBundle内存对象

private IEnumerator LoadMainGameObject(string path) 
{ 
	WWW bundle = new WWW(path); 
	yield return bundle; 
	//加载到游戏中 
	AssetBundle playerBundle = bundle.assetBundle;
} 

 

3.2  从内存数据流动态创建AB

WWW www = new WWW (url);
// Wait for download to complete
yield return www;
// Get the byte data
byte[] encryptedData = www.bytes;
// Decrypt the AssetBundle data
byte[] decryptedData = YourDecryptionMethod(encryptedData);
// Create an AssetBundle from the bytes array
AssetBundle bundle = AssetBundle.CreateFromMemory(decryptedData);


四、加载AssertBundle对象中的Assets

4.1 加载非场景资源

AssetBundle.Load()        加载AB中指定名字的Object
AssetBundle.LoadAsync()   异步加载AB中指定名字的Object
AssetBundle.LoadAll()     加载AB中的所有Objects

例子:

a、如果只有一个资源,则可以使用下面的方式直接创建资源

Instantiate(bundle.assetBundle.mainAsset);

完整例子:

void Start () {
		StartCoroutine (LoadMainGameObject (serverPath + file));
	}
	
	//读取一个资源 
	private IEnumerator LoadMainGameObject(string path) 
	{ 
		WWW bundle = new WWW(path); 
		yield return bundle; 
		//加载到游戏中 
		yield return Instantiate(bundle.assetBundle.mainAsset); 
		bundle.assetBundle.Unload(false); 
	} 

 

b、多个资源

//通过Prefab的名称把他们都读取出来 
Object  obj0 =  bundle.assetBundle.Load("Prefab0"); 
Object  obj1 =  bundle.assetBundle.Load("Prefab1"); 
//加载到游戏中   
Instantiate(obj0); 
Instantiate(obj1);
完整例子:
//读取多个资源    
private IEnumerator LoadALLGameObject(string path) 
{ 
	WWW bundle = new WWW(path); 
	yield return bundle; 
	//通过Prefab的名称把他们都读取出来 
	Object  obj0 =  bundle.assetBundle.Load("Prefab0"); 
	Object  obj1 =  bundle.assetBundle.Load("Prefab1"); 
	//加载到游戏中   
	yield return Instantiate(obj0); 
	yield return Instantiate(obj1); 
	bundle.assetBundle.Unload(false); 
}



4.2 加载场景资源(即加载通过BuildPipeline.BuildStreamedSceneAssetBundle()的资源)

Application.LoadLevel()   销毁前一个Level的所有资源
Application.LoadLevelAsync()  销毁前一个Level的所有资源,异步加载
Application.LoadLevelAdditive()  不销毁前一个Level的资源
Application.LoadLevelAdditiveAsync() 不销毁前一个Level的资源,异步加载

例子:

private IEnumerator LoadScene() 
{ 
	WWW download = WWW.LoadFromCacheOrDownload ("file://"+Application.dataPath + "/MyScene.unity3d", 1); 
	yield return download; 
	var bundle = download.assetBundle; 
	Application.LoadLevel ("Level"); 
}

 

4.3 注意

如果是本地下载的情况下路径的写法是file:// + path(你的资源的路径),如file:///E:/test.unity3d,上面代码中的Application.dataPath的路径是项目下的Asserts目录下的路径


五、实例Assert对象

直接使用Instantiate即可,如

Instantiate(bundle.assetBundle.mainAsset

 

六、释放Assert Bundle 和 Asserts

AssetBundle.Unload(false)    仅释放Asset Bundle本身
AssetBundle.Unload(true)     释放Asset Bundle以及从它加载的Assets
Resource.UnloadUnusedAssets()   仅释放没有引用的Assets


说明:

1、如果Upload传入值为true,那么这个时候不仅是Aseset Bundle这个对象会被销毁,就连从这个AB对象加载出来的所有资源比如人物、场景,物体等都会被销毁,如果传入的值为false,那么只会销毁AB对象,销毁后也不能继续加载其他Assert了,同时所有从这个AB对象加载出来的Assert也没有应用了,因此这时候可以使用Resource.UnloadUnusedAssets()来释放所有没有引用的资源,记住使用GameObject.Destroy()仅能释放GameObject本身

 2、区别资源与游戏对象,资源相当于prefabs,Upload(true)仅仅是去掉资源Assert,但是已经实例化的对象是不会被销毁的,而所有的这些游戏对象都是从Assert来的,Assert被释放后就只是不能再实例化Assert里面的资源,如果要销毁Assert实例化出来的游戏物体还是需要使用GameObject.Destroy()

七、其他
Caching.CleanCache(); //清空缓存,调试的时候可用

 

声明:该文观点仅代表作者本人,牛骨文系教育信息发布平台,牛骨文仅提供信息存储空间服务。