一、前言
加载AssetBundle
的时候,如果AssetBundle
依赖了另一个AssetBundle
,则需要加载依赖的这个AssetBundle
。本文我将演示一下具体过程。
二、打AssetBundle
如下,有一个球体Sphere
预设,它对应的AssetBundle
设置为test
。
Sphere
依赖了材质球Material
,材质球的AssetBundle
设置为test2
。
我们在Editor
中写个打包AssetBundle
工具。
using UnityEngine;
using UnityEditor;
public class BuildAB
{
[MenuItem("Tools/BuildAB")]
public static void StartBuild()
{
//打包AssetBundle,输出目录Application.streamingAssetsPath
BuildPipeline.BuildAssetBundles(Application.streamingAssetsPath,
BuildAssetBundleOptions.ChunkBasedCompression,
BuildTarget.StandaloneWindows);
}
}
打出来的AssetBundle
文件如下
我们可以看到,除了
test
和test2
,还生成了一个StreamingAssets
,这个StreamingAssets
里面就记录了各个AssetBundle
的依赖关系,我们可以打开StreamingAssets.manifest
看看具体信息
ManifestFileVersion: 0
CRC: 4101034694
AssetBundleManifest:
AssetBundleInfos:
Info_0:
Name: test
Dependencies:
Dependency_0: test2
Info_1:
Name: test2
Dependencies: {}
可以看到test
依赖了test2
三、编写加载AssetBundle管理器
为了方便管理加载,我们封装一个加载AssetBundle
的管理器,代码中注释我写得比较清楚,这里不啰嗦了。
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.IO;
public class AssetBundleLoaderMgr
{
/// <summary>
/// 初始化,加载AssetBundleManifest,方便后面查找依赖
/// </summary>
public void Init()
{
string streamingAssetsAbPath = Path.Combine(Application.streamingAssetsPath, "StreamingAssets");
AssetBundle streamingAssetsAb = AssetBundle.LoadFromFile(streamingAssetsAbPath);
m_manifest = streamingAssetsAb.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
}
/// <summary>
/// 加载AssetBundle
/// </summary>
/// <param name="abName">AssetBundle名称</param>
/// <returns></returns>
public AssetBundle LoadAssetBundle(string abName)
{
AssetBundle ab = null;
if (!m_abDic.ContainsKey(abName))
{
string abResPath = Path.Combine(Application.streamingAssetsPath, abName);
ab = AssetBundle.LoadFromFile(abResPath);
m_abDic[abName] = ab;
}
else
{
ab = m_abDic[abName];
}
//加载依赖
string[] dependences = m_manifest.GetAllDependencies(abName);
int dependenceLen = dependences.Length;
if (dependenceLen > 0)
{
for (int i = 0; i < dependenceLen; i++)
{
string dependenceAbName = dependences[i];
if (!m_abDic.ContainsKey(dependenceAbName))
{
AssetBundle dependenceAb = LoadAssetBundle(dependenceAbName);
m_abDic[dependenceAbName] = dependenceAb;
}
}
}
return ab;
}
/// <summary>
/// 从AssetBundle中加载Asset
/// </summary>
/// <typeparam name="T">类型</typeparam>
/// <param name="abName">AssetBundle名</param>
/// <param name="assetName">Asset名</param>
/// <returns></returns>
public T LoadAsset<T>(string abName, string assetName) where T : Object
{
AssetBundle ab = LoadAssetBundle(abName);
T t = ab.LoadAsset<T>(assetName);
return t;
}
/// <summary>
/// 缓存加载的AssetBundle,防止多次加载
/// </summary>
private Dictionary<string, AssetBundle> m_abDic = new Dictionary<string, AssetBundle>();
/// <summary>
/// 它保存了各个AssetBundle的依赖信息
/// </summary>
private AssetBundleManifest m_manifest;
/// <summary>
/// 单例
/// </summary>
private static AssetBundleLoaderMgr s_instance;
public static AssetBundleLoaderMgr instance
{
get
{
if (null == s_instance)
s_instance = new AssetBundleLoaderMgr();
return s_instance;
}
}
}
四、运行测试
编写一个测试脚本,代码如下
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Main : MonoBehaviour
{
void Awake()
{
//初始化
AssetBundleLoaderMgr.instance.Init();
}
void Start()
{
//从test中加载Sphere预设
GameObject prefab = AssetBundleLoaderMgr.instance.LoadAsset<GameObject>("test", "Sphere");
//实例化预设
Instantiate(prefab);
}
}
运行效果,可以看到球体和依赖的材质都正常加载了。
五、如果不加载依赖
如果我们把加载依赖的代码注释掉,不加载依赖,如下
现在我们再运行测试下,可以看到
Sphere
球体的材质球丢失了。如果不想额外去加载
Sphere
球体的依赖,我们可以将材质球的AssetBundle
设置为None
,这样打出来的test
就会将材质球一并打进去。由于
test
包含了材质球的资源,所以文件比之前的大了一些。这个时候,我们查看
StreamingAssets.manifest
,可以看到test
已经不依赖其他的AssetBundle
了
ManifestFileVersion: 0
CRC: 153515353
AssetBundleManifest:
AssetBundleInfos:
Info_0:
Name: test
Dependencies: {}
此时,直接加载test
,可正常加载Sphere
球体。
好了,如果你你有什么疑问,可以在评论区留言。