本文由 祝你万事顺利 出品,转载请注明出处。
官方开源的AssetBundle Manager Demo。AssetBundle Manager是官方推出的一个AB包管理器,但是此管理器已经不再AssetStore中支持了,通过上面的链接我们仍然可以看到AB包管理器实现的源码。
这里官方的Demo作为一个参考,实际使用根据项目的具体情况会有所不同,本文对官方的Demo进行解析,在实际使用中对Manager要根据使用的具体情况进行一些自定义的改进。事实上,我们能看到官方对AssetBundleManagerDemo的更新到2018年下半年后面就没有更新了。但是在Unity2018以及更新的版本中,官方提出了新的解决方案AddressableAssetSystem此方案将Manager进行了封装,并做了很多改进优化,在后面的文章中,将进行新方案的解析。
在调用管理器的AB包加载方法之前,第一步要对AB包进行初始化,这一步加载StreamingAssets,在加载完成后,设置全局的AssetBundleManifest,这样我们才可以在后面正确的加载依赖。
public IEnumerator Initialize()
{
var request = AssetBundleManager.Initialize();
if (request != null)
{
yield return StartCoroutine(request);
}
}
IEnumerator Start()
{
yield return StartCoroutine(Initialize());
}
声明一个AssetBundleLoadOperation的请求。在请求完成后调用Operation中的GetAsset方法获取目标类型的资源。
IEnumerator Start()
{
yield return StartCoroutine(Initialize());
AssetBundleLoadOperation request = AssetBundleManager.LoadAssetBundle("commonpanel.prefab");
yield return StartCoroutine(request);
GameObject commonPanelB = request.GetAsset<GameObject>("CommonPanel");
Instantiate(commonPanelB);
}
void Unload()
{
AssetBundleManager.UnloadAssetBundle("commonpanel.prefab");
}
在官方的案例中我们挑出关键的资源加载和资源卸载的部分进行分析。这里对源码进行一些删减,仅分析核心的逻辑。
1.资源加载部分:资源的加载对外接口,希望使用者指定需要加载的资源名称和其所在的AB包名,这里使用者不需要加载AB包,而是在请求资源的时候系统内部进行AB包的加载。
static public AssetBundleLoadAssetOperation LoadAssetAsync(string assetBundleName, string assetName, System.Type type)
{
Log(LogType.Info, "Loading " + assetName + " from " + assetBundleName + " bundle");
AssetBundleLoadAssetOperation operation = null;
{
assetBundleName = RemapVariantName(assetBundleName);
LoadAssetBundle(assetBundleName);
operation = new AssetBundleLoadAssetOperationFull(assetBundleName, assetName, type);
m_InProgressOperations.Add(operation);
}
return operation;
}
2.AB包的加载在内部实现,AB包的加载采用异步的方式,这里会去请求一个Operation,将这个Operation添加到一个队列中,在Manager的Update中不断地检测Operation是否完成。
static protected void LoadAssetBundle(string assetBundleName)
{
LoadAssetBundle(assetBundleName, false);
}
static protected void LoadAssetBundle(string assetBundleName, bool isLoadingAssetBundleManifest)
{
Log(LogType.Info, "Loading Asset Bundle " + (isLoadingAssetBundleManifest ? "Manifest: " : ": ") + assetBundleName);
if (!isLoadingAssetBundleManifest)
{
if (m_AssetBundleManifest == null)
{
Log(LogType.Error, "Please initialize AssetBundleManifest by calling AssetBundleManager.Initialize()");
return;
}
}
bool isAlreadyProcessed = LoadAssetBundleInternal(assetBundleName, isLoadingAssetBundleManifest);
if (!isAlreadyProcessed && !isLoadingAssetBundleManifest)
LoadDependencies(assetBundleName);
}
static protected bool LoadAssetBundleInternal(string assetBundleName, bool isLoadingAssetBundleManifest)
{
// Already loaded.
LoadedAssetBundle bundle = null;
m_LoadedAssetBundles.TryGetValue(assetBundleName, out bundle);
if (bundle != null)
{
bundle.m_ReferencedCount++;
return true;
}
if (m_DownloadingBundles.Contains(assetBundleName))
return true;
string bundleBaseDownloadingURL = GetAssetBundleBaseDownloadingURL(assetBundleName);
if (bundleBaseDownloadingURL.ToLower().StartsWith("odr://"))
{
new ApplicationException("Can't load bundle " + assetBundleName + " through ODR: this Unity version or build target doesn't support it.");
}
else if (bundleBaseDownloadingURL.ToLower().StartsWith("res://"))
{
new ApplicationException("Can't load bundle " + assetBundleName + " through asset catalog: this Unity version or build target doesn't support it.");
}
else
{
WWW download = null;
if (!bundleBaseDownloadingURL.EndsWith("/"))
{
bundleBaseDownloadingURL += "/";
}
string url = bundleBaseDownloadingURL + assetBundleName;
if (isLoadingAssetBundleManifest)
download = new WWW(url);
else
download = WWW.LoadFromCacheOrDownload(url, m_AssetBundleManifest.GetAssetBundleHash(assetBundleName), 0);
m_InProgressOperations.Add(new AssetBundleDownloadFromWebOperation(assetBundleName, download));
}
m_DownloadingBundles.Add(assetBundleName);
return false;
}
3.Operation的设计,Operation继承IEnumerator,所有的资源加载会继承Operation的基类
public abstract class AssetBundleLoadOperation : IEnumerator
{
public object Current
{
get
{
return null;
}
}
public bool MoveNext()
{
return !IsDone();
}
public void Reset()
{
}
abstract public bool Update();
abstract public bool IsDone();
}
参考文章:
Unity5-ABSystem(五):AssetBundle内存