Unity5新的AssetBundle系统使用心得
Unity的AssetBundle系统是对资源管理的一个扩展,动态更新,网页游戏,资源下载都是基于AssetBundle系统的。但是不得不说,这个系统非常恶心,坑很深。至于有多深,请看这篇文章: http://www.cnblogs.com/ybgame/p/3973177.html
原先的AssetBundle系统需要自己写一大坨导出的代码(BuildPipeline),这个新手会无从下手,老手也经常会被坑到。想正确处理好资源的依赖关系从而保证资源完整而又不会产生重复资源,确实不是一件非常容易的事情。
Unity5新的AssetBundle系统大大简化了这一操作。Unity打包的时候会自动处理依赖关系,并生成一个.manifest文件,这个文件描述了assetbundle包大小、crc验证、包之间的依赖关系等等,是一个文本文件。加载资源的时候Unity会自动处理好其依赖包的加载。
打包代码简化为一个函数(其实也没什么必要了,因为流程固定了,做成内嵌的菜单选项也没什么影响)
BuildPipeline.BuildAssetBundles(outputPath);
执行这个函数,它会自动打包工程目录下的所有的assetbundle,函数足够智能,它只会打包有修改的资源。
如何添加一个AssetBundle呢?
很简单,在资源属性窗口底部有一个选项,这个地方设置AssetBundle的名字。它会修改资源对应的.meta文件,记录这个名字。 AssetBundle的名字固定为小写。另外,每个AssetBundle都可以设置一个Variant,其实就是一个后缀,实际AssetBundle的名字会添加这个后缀。如果有不同分辨率的同名资源,可以使用这个来做区分。
我手头的模型资源非常多,所以我又写了个脚本自动遍历prefab的meta文件,添加AssetBundle名字。有一个需要注意的地方就是.meta文件貌似权限问题,无法直接写入,需要删除原文件,然后使用新的文件替换。。
# -*- coding: utf-8 -*-
import os, sys, shutil;
EXT_LIST = ['.prefab.meta', '.png.meta', '.jpg.meta'];
def doWork(path):
for root, dirs, files in os.walk(path):
for file in files:
for ext in EXT_LIST:
if file.endswith(ext):
fullPath = os.path.join(root, file)
fullPath = fullPath.replace('\\', '/')
prefabName = fullPath.replace(path, '');
prefabName = prefabName[:prefabName.find('.')] + '.data';
fileData = [];
fp = open(fullPath, 'r');
for line in fp:
if line.find('assetBundleName:') != -1:
fileData.append(' assetBundleName: ' + prefabName.lower() + '\n');
else:
fileData.append(line);
fp.close();
# os.remove(fullPath);
# return;
fpw = open(fullPath + '.tmp', 'w');
fpw.writelines(fileData);
fpw.close();
os.remove(fullPath)
shutil.copy(fullPath + '.tmp', fullPath);
os.remove(fullPath + '.tmp')
break;
doWork(r'Assets/Resources/Prefab/')
os.system('PAUSE')c#编辑器扩展(与python代码功能一样,喜欢哪个用哪个)
public class ExportAssetBundles : Editor
{
// 设置assetbundle的名字(修改meta文件)
[MenuItem("Tools/SetAssetBundleName")]
static void OnSetAssetBundleName()
{
UnityEngine.Object obj = Selection.activeObject;
string path = AssetDatabase.GetAssetPath(Selection.activeObject);
string[] extList = new string[] { ".prefab.meta", ".png.meta", ".jpg.meta" , ".tga.meta" };
EditorUtil.Walk(path, extList, DoSetAssetBundleName);
//刷新编辑器
AssetDatabase.Refresh();
Debug.Log("AssetBundleName修改完毕");
}
static void DoSetAssetBundleName(string path)
{
path = path.Replace("\\", "/");
int index = path.IndexOf(EditorConfig.PREFAB_PATH);
string relativePath = path.Substring(path.IndexOf(EditorConfig.PREFAB_PATH) + EditorConfig.PREFAB_PATH.Length);
string prefabName = relativePath.Substring(0, relativePath.IndexOf('.')) + EditorConfig.ASSETBUNDLE;
StreamReader fs = new StreamReader(path);
List<string> ret = new List<string>();
string line;
while((line = fs.ReadLine()) != null) {
line = line.Replace("\n", "");
if (line.IndexOf("assetBundleName:") != -1) {
line = " assetBundleName: " + prefabName.ToLower();
}
ret.Add(line);
}
fs.Close();
File.Delete(path);
StreamWriter writer = new StreamWriter(path + ".tmp");
foreach (var each in ret) {
writer.WriteLine(each);
}
writer.Close();
File.Copy(path + ".tmp", path);
File.Delete(path + ".tmp");
}
[MenuItem("Tools/CreateAssetBundle")]
static void OnCreateAssetBundle()
{
BuildPipeline.BuildAssetBundles(EditorConfig.OUTPUT_PATH);
//刷新编辑器
AssetDatabase.Refresh();
Debug.Log("AssetBundle打包完毕");
}
}