Assetbundle可以将Prefab封装起来,这是多么方便啊! 而且我也强烈建议大家将Prefab封装成Assetbundle,因为Prefab可以将游戏对象身上带的游戏游戏组件、游戏脚本、材质都封装在一起。当从服务器上将Assetbundle下载以后直接Instantiate就可以放入游戏中。

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

如果打包场景的话那么内存与size就是 公用模型的size * N个场景,想想其实挺恐怖的。其实我们可以巧妙的使用,首先把场景中公用的部分和私有的部分统统放入Unity, 然后烘培整个场景。 当场景烘培完毕后把公用的模型部分在拿出去,场景只只保留私有的模型。还可以做一个工具将公用模型在场景中的坐标保存在XML中(每个场景文件会对应一个公用模型的XML信息),最后在将公用的模型分别封装在别的Assetbundle中。

服务器上提供每个场景的Assetbundle ,和公用模型的Assetbundle,一般公用模型的Assetbundle可以放在常驻内存中(可能使用频繁、根据项目的不同而定)场景Assetbundle下载完毕后,现载入场景然后在根据场景对应的XML信息将公用模型部分动态的在添加到场景中,这样就完成了一个场景的构建。

Prefab打包技巧: Prefab打包时自身是不占多少空间的 <=1KB  但是Prefab上是可以关联  这五大部分 “界面,模型,特效,声音,场景,脚本”以及在Hierarchy视图中 坐标/缩放/旋转。 关联这些信息以后就会很大,所以为了避免资源的浪费尽量避免Prefab重复关联。

一个prefab下面可以同时关联多个游戏对象 ,这里举个例子如果你的 Prefab下面放了一个模型 它的大小可能是500k  ,在 Prefab下面放了十个完全相同模型 它的大小可能是501k 。 如果Prefab下面放了两个不同的模型,它的大小可能就会是 500k x 2 的size  ,也就是说Prefab与关联的数量是无关的 。

加密部分: assetbundle 是可以转换成 字节数组 ,客户端与服务器约定一组解密 字节数组的算法就可以实现资源加密。

1、相同的模型尽量打包在一起,他们会公用一套资源文件。

2、相同模型具有不同的脚本、组件的话把他们放在不同的Prefab中,最后把这些Prefab一起打包在一个Assetbundle中

3、不相同的模型尽量分开打包

对在Project视图中选中的对象进行分开打包:

 [MenuItem("Custom Editor/Create AssetBunldes Main")]
static void CreateAssetBunldesMain()
{
//获取在Project视图中选择的所有游戏对象
Object[] SelectedAsset = Selection.GetFiltered(typeof(Object), SelectionMode.DeepAssets);
//遍历所有的游戏对象
foreach (Object obj in SelectedAsset)
{
string sourcePath = AssetDatabase.GetAssetPath(obj);
//本地测试:建议最后将Assetbundle放在StreamingAssets文件夹下,如果没有就创建一个,因为移动平台下只能读取这个路径
//StreamingAssets是只读路径,不能写入
//服务器下载:就不需要放在这里,服务器上客户端用www类进行下载。
string path = CreatePath();
string targetPath = path + obj.name + ".assetbundle";
if (BuildPipeline.BuildAssetBundle(obj, null, targetPath, BuildAssetBundleOptions.CollectDependencies))
{
Debug.Log(obj.name + "资源打包成功");
}
else
{
Debug.Log(obj.name + "资源打包失败");
}
}
//刷新编辑器
AssetDatabase.Refresh();
}

对在Project视图中选中的对象进行统一打包,打包成一个AB:

 [MenuItem("Custom Editor/Create AssetBunldes ALL")]
static void CreateAssetBunldesALL()
{
Caching.CleanCache(); string path = CreatePath();
string Path = path + "ALL.assetbundle"; Object[] SelectedAsset = Selection.GetFiltered(typeof(Object), SelectionMode.DeepAssets); //这里注意第二个参数就行
if (BuildPipeline.BuildAssetBundle(null, SelectedAsset, Path, BuildAssetBundleOptions.CollectDependencies))
{
AssetDatabase.Refresh();
}
else
{ }
} private static string CreatePath()
{
string path = Application.dataPath + "/StreamingAssets/";
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
}
return path;
}

BuildPipeline.BuildAssetBundle (obj, null, targetPath, BuildAssetBundleOptions.CollectDependencies)

参数1:它只能放一个对象,因为我们这里是分别打包,所以通过循环将每个对象分别放在了这里。

参数2:可以放入一个数组对象。

默认情况下打的包只能在电脑上用,如果要在手机上用就要添加一个参数。

Android上:BuildPipeline.BuildAssetBundle (obj, null, targetPath, BuildAssetBundleOptions.CollectDependencies,BuildTarget.Android)

IOS上:BuildPipeline.BuildAssetBundle (obj, null, targetPath, BuildAssetBundleOptions.CollectDependencies,BuildTarget.iPhone)

另外,电脑上和手机上打出来的Assetbundle不能混用,不同平台只能用自己的。

读取Assetbundle

然后我们来学习如何运行时读取Assetbundle,Assetbundle是可以同时放在服务器或者本地的,无论放在哪里两种下载读取的方式是完全一样的

 //不同平台下StreamingAssets的路径是不同的,这里需要注意一下。
public static readonly 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 void OnGUI()
{
//读取一个资源
if (GUILayout.Button("Main Assetbundle"))
{
StartCoroutine(LoadMainGameObject(PathURL + "Cube1.assetbundle"));
StartCoroutine(LoadMainGameObject(PathURL + "Cube2.assetbundle"));
}
//读取全部资源
if (GUILayout.Button("ALL Assetbundle"))
{
StartCoroutine(LoadALLGameObject(PathURL + "ALL.assetbundle"));
} } //读取一个资源
private IEnumerator LoadMainGameObject(string path)
{
WWW bundle = new WWW(path);
yield return bundle; //加载到游戏中 mainAsset只适用于ab里面只打包了一个对象
yield return Instantiate(bundle.assetBundle.mainAsset);
bundle.assetBundle.Unload(false);
} //读取全部资源
private IEnumerator LoadALLGameObject(string path)
{
WWW bundle = new WWW(path);
yield return bundle; //通过Prefab的名称把他们都读取出来
Object obj0 = bundle.assetBundle.Load("Cube1");
Object obj1 = bundle.assetBundle.Load("Cube2"); //加载到游戏中
yield return Instantiate(obj0);
yield return Instantiate(obj1);
bundle.assetBundle.Unload(false);
}

这里我们详细的说说 下载类WWW

WWW bundle = new WWW(path);

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

private IEnumerator LoadMainCacheGameObject(string path)
{
//如果缓存中没有此ab,就去网络上下载
WWW bundle = WWW.LoadFromCacheOrDownload(path,);
yield return bundle; //加载到游戏中
yield return Instantiate(bundle.assetBundle.mainAsset);
bundle.assetBundle.Unload(false);
}

使用的方法是WWW.LoadFromCacheOrDownload(path,5);

参数1:服务器或者本地下载地址

参数2:版本号

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

我们再聊聊Assetbundle 中的脚本,在移动平台下Assetbundle里面放的脚本是不会被执行的,还记得我们打包前给两个Prefab挂上了脚本吗?在手机上将Assetbundle下载到本地后,加载进游戏中Prefab会自动在本地找它身上挂着的脚本,他是根据脚本的名来寻找,如果本地有这条脚本的话,Prefab会把这个脚本重新绑定在自身,并且会把打包前的参数传递进来。如果本地没有,身上挂的条脚本永远都不会被执行。

如果你的Assetbundle中的Prefab上引用的对象,那么这样做就会出错了,你需要设定他们的依赖关系。或者运行时通过脚本动态的载入对象。

http://docs.unity3d.com/Documentation/ScriptReference/BuildPipeline.PopAssetDependencies.html

http://docs.unity3d.com/Documentation/ScriptReference/BuildPipeline.PushAssetDependencies.html

像这样重新打包就可以。但是,Unity官方表示这些方法都过时了,推荐使用Unity5.0以上的资源打包API了!可以避免很多坑!

2014年10月补充

WWW.LoadFromCacheOrDownload 这个方法建议大家以后不要再用了

因为是异步方法,而且还占用内存。

强烈建议使用AssetBundle.CreateFromFile 它是一个同步方法。现在IOS 和 android 都支持了,强烈建议用。

打包的时候需要选择不压缩。

//打包场景
BuildPipeline.BuildStreamedSceneAssetBundle(levels, path, target, BuildOptions.UncompressedAssetBundle))
//打包资源
BuildPipeline.BuildAssetBundle(null, assets, path, BuildAssetBundleOptions.UncompressedAssetBundle | BuildAssetBundleOptions.CollectDependencies, target);

因为不压缩, 所以就需要我们自己来压缩资源了, 可以用LZMA 和 GZIP来进行压缩。

1.打包出来的Assetbundle我们自己用LZMA压缩,上传到服务器上。

2.IOS或者Android下载这些assetbundle

3.解压缩这些assetbundle并且保存在Application.persistentDataPath 目录下。

4.以后通过AssetBundle.CreatFromFile  读取assetbundle。

此法确实可行,我们已经在实际项目中轰轰烈烈的使用了。。

http://www.xuanyusong.com/archives/2405

Assetbundle2的更多相关文章

  1. Unity AssetBundles and Resources指引 (三) AssetBundle基础

    本文内容主要翻译自下面这篇文章 https://unity3d.com/cn/learn/tutorials/topics/best-practices/guide-assetbundles-and- ...

  2. Siki_Unity_3-7_AssetBundle从入门到掌握

    Unity 3-7 AssetBundle从入门到掌握 任务1&2&3:课程介绍 AssetBundle -- 用于资源的更新 为了之后的xLua (Lua热更新的框架)打下基础 任务 ...

随机推荐

  1. maven 项目运行找不到类

    其实maven 仓库有jar包,可能未编译或破损, 在本地仓删除它,然后maven install

  2. viewport原理和使用和设置移动端自适应的方法(移动适应电脑)

    viewport原理和使用和设置移动端自适应的方法 HTML中: <meta name="viewport" content="width=device-width ...

  3. File,FileInfo,Directory,DirectoryInfo

    两者的共同点:  一:都用于典型的操作,如复制.移动.重命名.创建.打开.删除和追加到文件   二:默认情况下,将向所有用户授予对新文件的完全读/写访问权限.  两者的区别:   File类是静态类, ...

  4. 【luogu P1726 上白泽慧音】 题解

    题目链接:https://www.luogu.org/problemnew/show/P1726 菜 #include <stack> #include <cstdio> #i ...

  5. 【题解】洛谷P2926 [USACO08DEC]拍头Patting Heads

    洛谷P2926:https://www.luogu.org/problemnew/show/P2926 思路 对于每一个出现的数 从1到Max 凡是这个数的倍数 那么ans就加上他的个数 PS:最后要 ...

  6. linux 使用sqlite3

    :c中使用sqlite3需要调用函数接口操作: sqlite3 *db; int status=sqlite_open("dbname",&db);//打开或者创建数据库 ...

  7. mui 的多图片上传

    pickHead(){ var _this = this; plus.gallery.pick(function(path){ _this.headImage=path; var files = [{ ...

  8. LeetCode13.罗马数字转整数 JavaScript

    罗马数字包含以下七种字符: I, V, X, L,C,D 和 M. 字符 数值 I 1 V 5 X 10 L 50 C 100 D 500 M 1000 例如, 罗马数字 2 写做 II ,即为两个并 ...

  9. JS继续学习记录(一)

    JS继续学习记录(一) 总感觉自己的js code写的还算可以,但是又深知好像只知道一些皮毛,所以打算仔细记录一下js晋级学习过程,日日往复 先记录一下自己目前对js的了解吧(20180828) js ...

  10. 快速解决Kali 更新失败问题

    Kali Linux 2018.4 初学者在安装完kali 系统后第一件事往往就是更新软件,但在更新过程中通常会出现各种各样的问题,比如更新提示不含有 'maincontrib' 组件,跳过配置文件 ...