Unity之资源打包Assetbundle
一、如何创建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(); //清空缓存,调试的时候可用
