当每次开发项目时,最基础也是最重要的莫过于资源管理了,对于u3d的资源管理,最方便的莫过于通过“配置标志位”来做到资源无缝在AssetBundle与Resources之间切换,如果要做到这个,前期的资源规范就非常重要了,在这里,我将提供一整套完整可用的方案,欢迎大家交流。
一、方案背景与限制
在unity3d 5.x中提供了新的AssetBundle打包方案,极大的减轻了AssetBundle的实现难度与维护成本,在新这种新的模式下,有以下2点注意:
1.每个资源的AssetBundle Lable中,都可以明确的指定资源名称,但是Lable中只能为小写
2.在每个资源的AssetBundle Lable中,都可以指定层级结构,用"/"隔开,在生成时会在指定目录下按照命名结构进行层级创建,如下图
生成后,目录结构如下图:
二、具体方案与对应资源规范
- 在游戏中的需要用到的预制件,在开发时,都放入到Resources目录下的指定类型的文件夹内,注意:此目录下的文件夹与资源名称只能是小写字母与'_'的组合,方便统一资源加载
- 生成的AssetBundle资源文件放在StreamingAssets目录下,至于发布时是解压到Application.persistentDataPath还是先查找Application.persistentDataPath目录,没有再读取StreamingAssets目录,由项目决定(但是需要注意的是:真机的StreamingAssets目录只能用www方法进行访问)
- 在标记Resources目录下资源的AssetBundle Lable时,内容为相对于Resources的目录结构+名称,如图所示
- 如果有2个或2个以上的Resources目录下预制件引用了同一个资源,需要将此资源独立设置一个AssetBundle Lable(建议根据在Asset目录下的相对目录进行设置,方便统一对比查找)
- U3d的一些内置资源默认会放入到最上层的AssetBundle包中,如果对冗余资源介意的话,需要把内置资源也生成为对应的依赖包
三、工具与代码范例(在unity3d 5.6.6下运行通过)
1.自动打包工具代码(里面的目录、平台大家可以根据实际情况进行替换,代码功能比较单一且插入代码的插件实在太搓了,我就去掉注释了)
[MenuItem("tool/creat asset")]
static void creatAsset()
{
Dictionary<string, int> m_pathAndTime = new Dictionary<string, int>();
List<GameObject> m_resObj = new List<GameObject>();
string m_countPath = "Effect/";
Object[] prefableArr = Resources.LoadAll(m_countPath);
if(prefableArr.Length == 0)
{Application.persistentDataPath }
else
{
for (int i = 0; i < prefableArr.Length; i++)
{
string tmpPath = AssetDatabase.GetAssetPath(prefableArr[i]);
string[] ObjPath = AssetDatabase.GetDependencies(tmpPath);
if(ObjPath.Length == 0)
{ }
else
{
for (int j = 0; j < ObjPath.Length; j++)
{
if (ObjPath[j].StartsWith("Assets/Resources"))
{ continue; }
else
{
string name = ObjPath[j].Replace("Assets/", "");
int count = 0;
if (m_pathAndTime.TryGetValue(name, out count))
{ m_pathAndTime[name] += 1; }
else
{ m_pathAndTime.Add(name, 1); }
}
}
}
}
foreach (var item in m_pathAndTime)
{
if (item.Value >= 2)
{
string name = "Assets/" + item.Key;
AssetImporter resAsset = AssetImporter.GetAtPath(name);
if (resAsset != null )
{
name = name.Replace("Assets/", "");
name = name.Substring(0, name.LastIndexOf('.'));
resAsset.assetBundleName = name;
}
}
else
{
}
}
for (int i = 0; i < prefableArr.Length; i++)
{
string tmpPath = AssetDatabase.GetAssetPath(prefableArr[i]);
string[] ObjPath = AssetDatabase.GetDependencies(tmpPath);
for (int j = 0; j < ObjPath.Length; j++)
{
if (ObjPath[j].StartsWith("Assets/Resources/"))
{
AssetImporter resAsset = AssetImporter.GetAtPath(ObjPath[j]);
if (resAsset != null)
{
string name = ObjPath[j].Substring(0, ObjPath[j].LastIndexOf('.'));
name = name.Replace("Assets/Resources/", "");
resAsset.assetBundleName = name;
}
}
}
}
BuildPipeline.BuildAssetBundles(Application.dataPath + "/StreamingAssets", BuildAssetBundleOptions.ChunkBasedCompression,BuildTarget.StandaloneWindows);
AssetDatabase.Refresh();
}
}
2.清除之前的所有AssetBundle Lable内容
[MenuItem("tool/clean all res")]
static void CleanAbInfo()
{
string[] allLabName = AssetDatabase.GetAllAssetBundleNames();
for (int i = 0; i < allLabName.Length; i++)
{
AssetDatabase.RemoveAssetBundleName(allLabName[i], true);
}
Resources.UnloadUnusedAssets();
}
3.调试加载工具(可以直接挪入到资源管理器中,每个项目的资源管理都不太一样,我就不单独放我的资源管理类了)
[MenuItem("tool/test load ab")]
static void LoadAb()
{
//
AssetBundle assetBundleManifest = AssetBundle.LoadFromFile(Application.dataPath + "/AssetBundles/AssetBundles");
if (null != assetBundleManifest)
{
AssetBundleManifest manifest = assetBundleManifest.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
if (manifest != null)
{
//AssetBundle testBundle = AssetBundle.LoadFromFile(Application.dataPath + "/AssetBundles/effect/link12");
//if (null != testBundle)
{
string[] allDepends = manifest.GetAllDependencies("effect/link12");
AssetBundle[] dependAsset = new AssetBundle[allDepends.Length];
for (int i = 0; i < allDepends.Length; i++)
{
string pathName = Application.dataPath + "/AssetBundles/" + allDepends[i];
dependAsset[i] = AssetBundle.LoadFromFile(pathName);
if(dependAsset[i] == null)
{ Debug.LogError("引用资源没有找到"+ pathName); }
else
{ /*Object[] has = dependAsset[i].LoadAllAssets();*/ }
}
AssetBundle testBundle = AssetBundle.LoadFromFile(Application.dataPath + "/AssetBundles/effect/link12");
if (null != testBundle)
{
GameObject needInfo = testBundle.LoadAsset("link12") as GameObject;
if (needInfo != null)
{
GameObject ui = (GameObject)Instantiate(needInfo);
}
}
for (int i = 0; i < allDepends.Length; i++)
{
if(dependAsset[i] != null)
{
dependAsset[i].Unload(false);
}
}
testBundle.Unload(false);
}
assetBundleManifest.Unload(false);
}
}
Resources.UnloadUnusedAssets();
}