一、简介
马三在公司大部分时间做的都是游戏业务逻辑和编辑器工具等相关工作,因此对Unity AssetBundle这块的知识点并不是很熟悉,自己也是有打算想了解并熟悉一下AssetBundle,掌握一下Unity资源管理方面的知识,因此有了这篇博客。
我会在博客中整理出一些自己学习时收集到的一些比较好的AssetBundle学习资料,并且结合现在正在参与开发的商业项目随时写下一些自己的拙见。本篇博客权当是马三自己的笔记和一些杂谈,会不断地随时随地的更新一些内容。
二、收集整理的一些AssetBundle资料
1.Unity AssetBundle5讲系列
Unity5-ABSystem(一):AssetBundle原理
Unity5-ABSystem(二):AssetBundle导出
Unity5-ABSystem(三):AssetBundle加载
Unity5-ABSystem(四):AssetBundle依赖
Unity5-ABSystem(五):AssetBundle内存
2.慕容小匹夫系列
Unity3D 5.3 新版AssetBundle使用方案及策略
3.何三思译Unity AssetBundle官方文档系列
【Unity3D技术文档翻译】第1.0篇 AssetBundles
【Unity3D技术文档翻译】第1.1篇 AssetBundle 工作流
【Unity3D技术文档翻译】第1.2篇 为打包 AssetBundles 准备资产
【Unity3D技术文档翻译】第1.3篇 创建 AssetBundles
【Unity3D技术文档翻译】第1.4篇 AssetBundle 依赖关系
【Unity3D技术文档翻译】第1.5篇 本地使用 AssetBundles
【Unity3D技术文档翻译】第1.6篇 使用 AssetBundle Manager
【Unity3D技术文档翻译】第1.7篇 AssetBundles 补丁更新
【Unity3D技术文档翻译】第1.8篇 AssetBundles 问题及解决方法
【Unity3D技术文档翻译】第1.9篇 使用 Unity AssetBundle Browser tool (AssetBundle系列完结)
4.Unity AssetBundle官方文档
A guide to AssetBundles and Resources
5.Unity Assetbundles官方说明系列
Unity5.4 Assetbundles官方说明一(AssetBundles打包详解)
Unity5.4 Assetbundles官方说明二(AssetBundle压缩与解压)
Unity5.4 Assetbundles官方说明三(AssetBundle资源包的内部结构)
Unity5.4 Assetbundles官方说明四(AssetBundles的下载和加载)
Unity5.4 Assetbundles官方说明五(从AssetBundles的加载和卸载资源对象)
Unity5.4 Assetbundles官方说明六(保留下载的AssetBundle)
Unity5.4 Assetbundles官方说明七(在AssetBundle中存储和加载二进制数据)
Unity5.4 Assetbundles官方说明八(数据安全方面的处理)
Unity5.4 Assetbundles官方说明九(资源包中包含脚本文件)
Unity5.4 Assetbundles官方说明十(官方疑难问题解答)
Unity5.4 Assetbundles十一:遇到的坑和整理的打包和加载流程(资源包更新的简易框架)
6.未规划分类
Unity AssetBundle 从入门到掌握(适合初学者)
Unity资源处理机制(Assets/WWW/AssetBundle/...)读取和加载资源方式详解
Unity3D中实现按资源名称自动化命名打包AssetBundle
Unity AssetBundle加载音频,无法播放音效并报错的坑
Unity打包AssetBundle自动分析资源依赖关系(包括UGUI图集打包)
7.AssetBundle分组策略总结
逻辑实体分组
一个UI界面或者所有UI界面一个包(这个界面里面的贴图和布局信息一个包)
一个角色或者所有角色一个包(这个角色里面的模型和动画一个包)
所有的场景所共享的部分一个包(包括贴图和模型)
按照类型分组
所有声音资源打成一个包,所有shader打成一个包,所有模型打成一个包,所有材质打成一个包
按照使用分组
把在某一时间内使用的所有资源打成一个包。可以按照关卡分,一个关卡所需要的所有资源包括角色、贴图、声音等打成一个包。也可以按照场景分,一个场景所需要的资源一个包
注意
经常更新的资源放在一个单独的包里面,跟不经常更新的包分离
把需要同时加载的资源放在一个包里面
可以把其他包共享的资源放在一个单独的包里面
把一些需要同时加载的小资源打包成一个包
如果对于一个同一个资源有两个版本,可以考虑通过后缀来区分,例如v1、v2、v3
三、AssetBundle踩坑与经验集锦
1、先说一个遇到的坑,当大量(几百个)AssetBundle加载的时候(可能是WWW加载的时候,也可能是AssetBundle.LoadAsset的时候),Android手机上会闪退。看崩溃log是多线程文件访问的时候崩溃了。解决方法是减少同时加载的AB数量(这个是纯逻辑控制),使用AssetBundle.LoadFromFile接口。
2、打包AssetBundle使用LZ4压缩(BuildPipeline.BuildAssetBundles,第二个参数传递BuildAssetBundleOptions.ChunkBasedCompression),默认是LZMA压缩的,具有最高的压缩比。而替换为LZ4压缩,压缩比没有LZMA高,但是加载速度大幅提高。加载AssetBundle使用AssetBundle.LoadFromFile(Async),在Unity4的时候,只能使用WWW的接口来加载AB,因为CreateFromFile不支持压缩的AB。而Unity5的LoadFromFile是支持任意压缩格式的AB的。所以没有太大必要使用WWW了,而且这个接口像WWW.LoadFromCacheOrDownload接口一样,加载不压缩或者LZ4压缩格式的AB的时候是不会有额外的内存开销的。具体关于内存、加载速度的细节可以参考上面第三篇文章里面的介绍。
3、资源规划好一个独立的资源工程。规划好一系列的文件夹,在导入相应资源的时候自动通过AssetImporter设置好AB的名字。监测资源导入可以用AssetPostprocessor 。带动画的模型需要创建好prefab,而不带动画只是用于换装的模型可以直接导出,不需要创建prefab,因为这些模型我们只是取它的mesh数据。如果有打包图集,需要注意它和AB的匹配关系,举例来说,如果三张图片指定了同一个图集,而又分别指定了不同的AB名,则三个AB里面都包含了此图集(三张图片),这样就会造成严重的资源浪费。
4、AssetBundle.LoadFromFile接口在Android平台下也是可以直接访问StreamingAssets文件夹里面的内容的。5.4版本可以直接使用Application.streamingAssetsPath。而之前的版本需要使用 Application.dataPath + "!assets/" + filePath; 因为streamingAssetsPath带了jar://,这个是给WWW用的URL路径,而LoadFromFile接口需要的是实际路径(不带jar://也不带file://)。注意 !assets/ 这个地方叹号后面没有/。网上搜索到的各种写法都有,只有这个是正确的,注意此处细节。
四、Unity AssetBundle爬坑手记
文章转载自:http://www.cnblogs.com/ybgame/p/3973177.html
1 Object obj = AssetDatabase.LoadMainAssetAtPath("Assets/Test.png"); 2 BuildPipeline.BuildAssetBundle(obj, null, 3 Application.streamingAssetsPath + "/Test.assetbundle", 4 BuildAssetBundleOptions.CollectDependencies | BuildAssetBundleOptions.CompleteAssets 5 | BuildAssetBundleOptions.DeterministicAssetBundle, BuildTarget.StandaloneWindows);
在使用的时候,需要用WWW来加载Bundle,然后再用加载出来的Bundle来Load资源。
WWW w = new WWW("file://" + Application.streamingAssetsPath + "/Test.assetbundle"); myTexture = w.assetBundle.Load("Test");
Directory.GetFiles("Assets/MyDirs", "*.*", SearchOption.TopDirectoryOnly); Directory.GetDirectories(Application.dataPath + "/Resources/Game", "*.*", SearchOption.AllDirectories);
string newPath = "Assets" + mypath.Replace(Application.dataPath, ""); newPath = newPath.Replace("\", "/"); Object obj = AssetDatabase.LoadMainAssetAtPath(newPath);
在打对应的包之前应该先选择对应的平台再打包
string.Format("file://{0}/{1}", Application.streamingAssetsPath, bundlePath);
string.Format("jar:file://{0}!/assets/{1}", Application.dataPath, bundlePath);
IEnumerator LoadBundle(string url)
{
WWW www = = new WWW(url);
yield return www;
if (www.error != null)
{
Debug.LogError("Load Bundle Faile " + url + " Error Is " + www.error);
yield break;
}
//Do something ...
}
//将所有对象加载资源
Object[] objs = bundle.LoadAll();
//加载名为obj的资源
Object obj = bundle.Load("obj");
//异步加载名为resName,类型为type的资源
AssetBundleRequest res = bundle.LoadAsync(resName, type);
yield return res;
var obj = res.asset;
//需要先实例化
GameObject obj = GameObject.Instantiate(bundle.Load("MyPrefab")) as GameObject;

bundle.Load("MyPrefab", typeof(GameObject))
string path = Application.streamingAssetsPath;
BuildPipeline.PushAssetDependencies();
BuildTarget target = BuildTarget.StandaloneWindows;
BuildPipeline.BuildAssetBundle(AssetDatabase.LoadMainAssetAtPath("Assets/UI_tck_icon_houtui.png"), null,
path + "/package1.assetbundle",
BuildAssetBundleOptions.CollectDependencies | BuildAssetBundleOptions.CompleteAssets
| BuildAssetBundleOptions.DeterministicAssetBundle, target);
BuildPipeline.BuildAssetBundle(AssetDatabase.LoadMainAssetAtPath("Assets/New Material.mat"), null,
path + "/package2.assetbundle",
BuildAssetBundleOptions.CollectDependencies | BuildAssetBundleOptions.CompleteAssets
| BuildAssetBundleOptions.DeterministicAssetBundle, target);
BuildPipeline.PushAssetDependencies();
BuildPipeline.BuildAssetBundle(AssetDatabase.LoadMainAssetAtPath("Assets/Cube.prefab"), null,
path + "/package3.assetbundle",
BuildAssetBundleOptions.CollectDependencies | BuildAssetBundleOptions.CompleteAssets
| BuildAssetBundleOptions.DeterministicAssetBundle, BuildTarget.StandaloneWindows);
BuildPipeline.PopAssetDependencies();
BuildPipeline.PushAssetDependencies();
BuildPipeline.BuildAssetBundle(AssetDatabase.LoadMainAssetAtPath("Assets/Cubes.prefab"), null,
path + "/package4.assetbundle",
BuildAssetBundleOptions.CollectDependencies | BuildAssetBundleOptions.CompleteAssets
| BuildAssetBundleOptions.DeterministicAssetBundle, target);
BuildPipeline.PopAssetDependencies();
BuildPipeline.PopAssetDependencies();




[Serializable]
public class ResConfigData
{
public string ResName; //资源名字
public string BundleName; //包名字
public string Path; //资源路径
public int Vesrion; //版本号
}
[System.Serializable]
public class ResConfig : ScriptableObject
{
public List<ResConfigData> ConfigDatas = new List<ResConfigData>();
}
ResConfig obj = (ResConfig)AssetDatabase.LoadAssetAtPath(path, typeof(ResConfig));
if (obj == null)
{
obj = ScriptableObject.CreateInstance<ResConfig>();
AssetDatabase.CreateAsset(obj, path);
}
EditorUtility.SetDirty(obj);
