Unity5增加了新的打包AssetBundle方式-> BuildPipeline.BuildAssetBundles,大体思想是把资源以及依赖项分别打包,并用文本记录它们间的依赖关系,这种方式相对旧版本将资源粗暴的打成一个包来说,带来的好处也显而易见,每个资源以及依赖项都只打包一次不会造成依赖循环(不了解的同学可以看一下Unity AssetBundle爬坑手记 - 夜阑卧听风吹雨),但同时打包后的资源更碎片化,导致加载耗时更多。大家都有复制文件的经验,复制一个包比复制一堆碎文件快(同大小的两份文件)同样道理。
思想上有点类似李总(李剑英)的资源热更新方案,将资源信息(布局,参数等)解析成文本,使用的时候只需下载文本文件(占用物理内存小),再根据文本文件生成资源。但据我测试,BuildPipeline.BuildAssetBundles执行效率较低,在加载相同prefab的前提下根据文本生成prefab耗时51.59ms,使用BuildPipeline.BuildAssetBundles 加载耗时约118ms。这里只给大家一个大概的参考。
1. 打包AssetBundle,代码来源http://blog.csdn.net/onafioo/article/details/50969945, 稍作修改增加了自动关联依赖项的方法
using UnityEngine;
using System.Collections;
using UnityEditor;
using System.IO;
///
/// 把Resource下的资源打包成.data到OutPut目录下
///
public class Builder : Editor
{
public static string sourcePath = Application.dataPath + "/Resource";
const string AssetBundlesOutputPath = "Assets/OutPut";
[MenuItem("Custom/BuildAssetBundle")]
public static void BuildAssetBundle()
{
ClearAssetBundlesName();
Pack(sourcePath);
string outputPath = Path.Combine(AssetBundlesOutputPath, Platform.GetPlatformFolder(EditorUserBuildSettings.activeBuildTarget));
if (!Directory.Exists(outputPath))
{
Directory.CreateDirectory(outputPath);
}
//根据BuildSetting里面所激活的平台进行打包 设置过AssetBundleName的都会进行打包
BuildPipeline.BuildAssetBundles(outputPath, 0, EditorUserBuildSettings.activeBuildTarget);
AssetDatabase.Refresh();
Debug.Log("打包完成");
}
///
/// 清除之前设置过的AssetBundleName,避免产生不必要的资源也打包
/// 之前说过,只要设置了AssetBundleName的,都会进行打包,不论在什么目录下
///
static void ClearAssetBundlesName()
{
int length = AssetDatabase.GetAllAssetBundleNames().Length;
Debug.Log(length);
string[] oldAssetBundleNames = new string[length];
for (int i = 0; i < length; i++)
{
oldAssetBundleNames[i] = AssetDatabase.GetAllAssetBundleNames()[i];
}
for (int j = 0; j < oldAssetBundleNames.Length; j++)
{
AssetDatabase.RemoveAssetBundleName(oldAssetBundleNames[j], true);
}
length = AssetDatabase.GetAllAssetBundleNames().Length;
Debug.Log(length);
}
static void Pack(string source)
{
//Debug.Log("Pack source " + source);
DirectoryInfo folder = new DirectoryInfo(source);
FileSystemInfo[] files = folder.GetFileSystemInfos();
int length = files.Length;
for (int i = 0; i < length; i++)
{
if (files[i] is DirectoryInfo)
{
Pack(files[i].FullName);
}
else
{
if (!files[i].Name.EndsWith(".meta"))
{
fileWithDepends(files[i].FullName);
}
}
}
}
//设置要打包的文件
static void fileWithDepends(string source)
{
Debug.Log("file source " + source);
string _source = Replace(source);
string _assetPath = "Assets" + _source.Substring(Application.dataPath.Length);
Debug.Log(_assetPath);
//自动获取依赖项并给其资源设置AssetBundleName
string[] dps = AssetDatabase.GetDependencies(_assetPath);
foreach (var dp in dps)
{
Debug.Log("dp " + dp);
if (dp.EndsWith(".cs"))
continue;
AssetImporter assetImporter = AssetImporter.GetAtPath(dp);
string pathTmp = dp.Substring("Assets".Length + 1);
string assetName = pathTmp.Substring(pathTmp.IndexOf("/") + 1);
assetName = assetName.Replace(Path.GetExtension(assetName), ".data");
Debug.Log(assetName);
assetImporter.assetBundleName = assetName;
}
}
//设置要打包的文件
static void file(string source)
{
Debug.Log("file source " + source);
string _source = Replace(source);
string _assetPath = "Assets" + _source.Substring(Application.dataPath.Length);
string _assetPath2 = _source.Substring(Application.dataPath.Length + 1);
//Debug.Log (_assetPath);
//在代码中给资源设置AssetBundleName
AssetImporter assetImporter = AssetImporter.GetAtPath(_assetPath);
string[] dps = AssetDatabase.GetDependencies(_assetPath);
foreach (var dp in dps)
{
Debug.Log("dp " + dp);
}
string assetName = _assetPath2.Substring(_assetPath2.IndexOf("/") + 1);
assetName = assetName.Replace(Path.GetExtension(assetName), ".unity3d");
Debug.Log(assetName);
assetImporter.assetBundleName = assetName;
}
static string Replace(string s)
{
return s.Replace("\\", "/");
}
}
public class Platform
{
public static string GetPlatformFolder(BuildTarget target)
{
switch (target)
{
case BuildTarget.Android:
return "Android";
case BuildTarget.iOS:
return "IOS";
case BuildTarget.WebPlayer:
return "WebPlayer";
case BuildTarget.StandaloneWindows:
case BuildTarget.StandaloneWindows64:
return "Windows";
case BuildTarget.StandaloneOSXIntel:
case BuildTarget.StandaloneOSXIntel64:
case BuildTarget.StandaloneOSXUniversal:
return "OSX";
default:
return null;
}
}
}
2.加载AssetBundle
using UnityEngine;
using System.Collections;
using System;
public class TestLoadNewAB : MonoBehaviour
{
void OnGUI()
{
if (GUILayout.Button("LoadAssetbundle"))
{
DateTime t0 = DateTime.Now;
//首先加载Manifest文件;
AssetBundle manifestBundle = AssetBundle.LoadFromFile(Application.streamingAssetsPath
+ "/Android/Android");
Debug.Log(manifestBundle == null);
if (manifestBundle != null)
{
AssetBundleManifest manifest = (AssetBundleManifest)manifestBundle.LoadAsset("AssetBundleManifest");
Debug.Log(manifest == null);
//获取依赖文件列表;
string[] cubedepends = manifest.GetAllDependencies("cube.data");
Debug.Log(cubedepends.Length);
foreach (var item in cubedepends)
{
Debug.Log("depends " + item);
}
AssetBundle[] dependsAssetbundle = new AssetBundle[cubedepends.Length];
for (int index = 0; index < cubedepends.Length; index++)
{
//加载所有的依赖文件;
dependsAssetbundle[index] = AssetBundle.LoadFromFile(Application.streamingAssetsPath + "/Android/" + cubedepends[index]);
}
DateTime t1 = DateTime.Now;
//加载我们需要的文件;"
AssetBundle cubeBundle = AssetBundle.LoadFromFile(Application.streamingAssetsPath + "/Android/cube.data");
Debug.Log(cubeBundle == null);
GameObject cube = cubeBundle.LoadAsset("cube") as GameObject;
Debug.Log(cube == null);
if (cube != null)
{
Instantiate(cube);
DateTime t2 = DateTime.Now;
Debug.Log("LoadView Time1:" + (t1 - t0).TotalMilliseconds + " Time2:" + (t2 - t1).TotalMilliseconds);//+ " Time3:" + (t3 - t2).TotalMilliseconds
}
}
}
}
}