基本介绍:
什么是? 一个assets的集合,打包以用来在运行时加载
在应用中动态的 加载和卸载 新内容。 比如说DLC(downloadable content)

用处?

降低磁盘空间的消耗(第一次发布时) + 热更新资源

AssetBundle 使用LZMA进行压缩,并且相似的Prefabs在打包时能够大大减少空间占用。


创建AssetBundle,使用Editor代码,可以参考官方的manual:

 1 public class ExportAssetBundles
 2 {
 3     [MenuItem("Custom/Build AssetBundle From Selection - Track dependencies")]
 4     public static void ExportResource()
 5     {
 6         string path = EditorUtility.SaveFilePanel("Save Resource","","New Resource","unity3d");
 7         if(path.Length != 0)
 8         {
 9             Object[] selection = Selection.GetFiltered(typeof(Object), SelectionMode.DeepAssets);
10             BuildPipeline.BuildAssetBundle(Selection.activeObject,selection,path,
11                 BuildAssetBundleOptions.CollectDependencies|BuildAssetBundleOptions.CompleteAssets);
12             Selection.objects = selection;
13         }
14     }
15 
16     [MenuItem("Custom/Build AssetBundle From Selection - No dependency tracking")]
17     public static void ExportResourceNoTrack()
18     {
19         string path = EditorUtility.SaveFilePanel("Save Resource", "", "New Resource", "unity3d");
20         if(path.Length != 0)
21         {
22             
23             //BuildPipeline.BuildAssetBundle(Selection.activeObject, Selection.objects, path);
24             BuildPipeline.BuildAssetBundle(Selection.activeObject, Selection.objects, path);
25         }
26 
27     }
28 
29 }

下载:

 1 public class LoadAssetBundle : MonoBehaviour 
 2 {
 3     public Object obj;
 4 
 5     /// <summary>
 6     /// 
 7     /// </summary>
 8     /// <typeparam name="T"></typeparam>
 9     /// <param name="asset">bundle的名字</param>
10     /// <param name="url"></param>
11     /// <param name="version"></param>
12     /// <returns></returns>
13     public IEnumerator DownloadAssetBundle<T>(string asset,string url,int version) where T: Object
14     {
15         obj = null;
16 #if UNITY_EDITOR
17 
18         //prefab = Resources.LoadAssetAtPath("Assets/Artwork/mymodel.fbx", typeof(GameObject));
19         obj = Resources.LoadAssetAtPath("Assets/" + asset, typeof(T));
20         yield return null;
21 #else
22         while (!Caching.ready)
23             yield return null;
24         using(WWW www = WWW.LoadFromCacheOrDownload(url,version))
25         {
26             if (www.error != null)
27             {
28                 Debug.LogError("WWW download has an error "+www.error );                
29             }
30             else
31             {
32                 AssetBundle bundle = www.assetBundle;
33                 obj = bundle.Load(asset, typeof(T));
34                 bundle.Unload(false);
35             }
36         }
37 #endif
38     }
39 
40     

最好使用上述方式,但使用new WWW(url) 也是可以的。

上述代码中:Resources.loadAsssetAtPath 避免了重新打包assetbundel,这个函数的用处是 使你想load一个assetbundle一样laod它,它会跳过打包的过程来保证asset始终是最新的(简化操作)

 

.mainAsset 当制作assetbundle的时候的传递的第一个参数。
用处: 存储一个 textAsset 用来表示所有这个assetbundle中的objects信息。

使用注意:

url 使用本地 之前加 file://

从AssetBundle中加载出来的prefab上的脚本是会执行的,只要本地有这个脚本,不然会出现警告:“The referenced script on this Behaviour is missing!” ,脚本不会执行。

如果想要动态的加载脚本,只能通过编译成dll,然后改为.bytes,再反射加载,再add component。这也是官方推荐的Android下热更新脚本的一种方式。


LodaAll 的问题:

首先,对于所有的load,必须要指定type,不然可能由于重名而出现莫名其妙的错误。具体原因可以参见这篇文章的相关介绍:http://www.cnblogs.com/ybgame/p/3973177.html?utm_source=tuicool
常见错误:
Object[] objects = bundle.LoadAll();///
Foreach(Object obj in Objects)
{
  Instantiate(obj);
}
注意: 每个prefab 会出来 4个clone;

如果是用 Object[] objects = bundle.LoadAll(Typeof(GameObject));
则: 出来2个clone;
原因:prefab 中包含了 model 的meshfilter。即prefab是包含model的。
解决方法:不是将prefab打包,而是仅仅将model打包。这样就只有一个。

但是如果需要的不仅仅是模型,还要通过加入其他组件,那么就只能采用 名字 来做了

bundle.Load(“name”,typepf(Gameobject));
再instantiate 则是一个。
//使用名字能够保证始终是一个。

考虑第一个AssetBundle的第一个 也就是 mainAsset 保存名字。然后再一一实例化。

另一种:

也可以将这一步放在加载的时候,先加载TextAsset,然后获得名字。
AssetBundle bundle = www.assetBundle;
//textAsset 名称为Names
TextAsset file = bundle.Load("Names", typeof(TextAsset)) as TextAsset;
string content = file.text;
string[] names = content.Split(',');
foreach( string name in names)
{
Instantiate(bundle.Load(name, typeof(GameObject)));
}

 

关于打包的思路:

尽量把具有相同模型不同脚本的物体做成不同的prefab,然后打包在一起,可以较少空间占用。最后可以直接加载使用。
将大部分 在scene中出现的    存成  prefab。

然后 有些 prefab 只是脚本或者位置 或者其他不一样 ,那么这些放在一起打包 ,大大减小包的大小。

完全不关联的东西放  分开 打包。

基础UI可以打成一个包,重复使用

另外基础的场景背景 或者 公用背景 可以打在一起 ,每个场景不同的可以分开。

场景加载中使用Assetbundle的一些思路:

每次加载对应的场景的时候,需要场景对应的
AssetBundle url,每个 AssetBundle 中要加载哪些东西,这会对应着一个文件。然后去构建场景。
类似于MOMO的将场景保存为XML或者Json 文件。http://www.xuanyusong.com/archives/1919

大部分的场景都是基于同一个场景衍生的,所以可以做一个base场景,然后修改后save as

 

有效率的打包AssetBundle。
随着项目的增大,手动打包很繁杂,所以考虑程序去将项目中的所有需要打包的全部打包。
比如说 可以有一个 txt文件来map Asset –>Assetbundle。

 

由于WWW.LoadfromCacheOrDownload
是一个异步的过程,
解决方案:
1: 先优先加载 主角 或者 需要优先显示的部分,
再加载其他部分
2: 使用同步加载,AssetBundle.CreatFromFile
要求打包的时候不压缩,所以自己使用LZMA压缩,解压。
AssetBundle下载下来 并且 保存在 本地路径(比如说application.persistantDataPath),再使用AssetBundle.CreatFromFile 。

一个场景的完整的加载过程可能如下:
场景构成:
一个start脚本;
1:读取配置文件
2:加载公有的assetbundle
3:加载私有的assetbundle

具体还要看不同的情况。需要调节加载的顺序,因为会有相互的依赖性,不然可能会出现错误。

配置文件的示例:
Scene1.bytes:
公用bundle 路径(可以是相对的),公用bundle 路径(可以是相对的)| 私有bundle路径,私有bundle路径
分割符 ‘|’ ‘,’
比如: 公用
Application.persistantDatapath + “/publicBundles”+”/road.assetbunlde”;

采用自己定义的格式就可以。

另外,有一个文件记录所有的assetbundle的当前版本,用来供读取。

posted on 2015-03-11 19:48  forhk  阅读(842)  评论(0编辑  收藏  举报