前置知识
AB包资源管理器的实现
此AB包管理器(ABManager)用于管理Unity中AssetBundle(AB包)的加载、资源获取和卸载操作。采用单例模式确保全局唯一实例,根据不同平台确定主包名称,在初始化时加载主包及其manifest文件,之后可同步或异步加载AB包和资源,同时管理已加载的AB包避免重复加载,也提供卸载AB包的功能。
细节部分
1. 单例模式
通过静态属性Instance实现单例模式。若实例为空,则创建一个名为AssetBundleManager的游戏对象,并为其添加ABManager组件。
2. 主包加载
- 主包名称确定:根据不同平台(Windows、MacOS、Android)通过预处理器指令返回不同的主包名称,若平台未知则返回
"Unknown"。 - 主包及manifest文件加载:在
Awake方法中,若主包未加载,则从默认路径加载主包及其manifest文件,并将主包添加到已加载AB包字典中。
3.同步加载
- AB包加载:
LoadAB方法检查AB包是否已加载,若未加载则从默认路径同步加载,并递归加载其依赖的AB包。 - 资源加载:
LoadRes方法先调用LoadAB确保AB包已加载,然后从AB包中同步加载指定资源。
4. 异步加载
- 采用协程实现异步加载,使用队列管理异步加载任务,避免多个异步加载任务同时执行造成混乱。
LoadResAsync方法将异步加载任务添加到队列或直接启动协程执行,loadABAsync方法异步加载AB包及其依赖的AB包,loadResAsync方法异步加载资源并在加载完成后调用回调函数。
5. 卸载操作
UnLoad方法卸载指定的AB包,可选择是否清除资源。UnLoadALL方法卸载所有AB包,可选择是否清除所有资源,并清空已加载AB包字典。
源码:
#define WINDOWS
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
public class ABManager :MonoBehaviour
{
private static ABManager instance;
public static ABManager Instance
{
get
{
if(instance == null)
{
GameObject obj = new GameObject("AssetBundleManager");
instance = obj.AddComponent<ABManager>();
}
return instance;
}
}
#region 主包
private string mainABName()
{
#if WINDOWS
return "PC";
#elif MACOS
return "MAC";
#elif ANDROID
return "Android";
#else
return "Unknown";
#endif
}//主包名字
private string defaultPath = Application.streamingAssetsPath;//默认路径
private AssetBundle mainAB = null;//主包
private AssetBundleManifest mainABManifest = null;//主包的manifest文件
void Awake()
{
//初始化即加载主包及其manifest文件
if (mainAB == null)
{
mainAB = AssetBundle.LoadFromFile(defaultPath + "/" + mainABName());
mainABManifest = mainAB.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
abDic.Add(mainABName(), mainAB);
}
}
#endregion
#region 基础操作
private Dictionary<string, AssetBundle> abDic=new Dictionary<string, AssetBundle>();//记录已经加载过的包,避免重复加载
#region 同步加载
public void LoadAB(string abName)
{
//如果已经加载过包,不再加载
if (abDic.ContainsKey(abName)) return;
try
{
AssetBundle ab = AssetBundle.LoadFromFile(defaultPath + "/" + abName);
abDic.Add(abName, ab);
//加载其所依赖的包
string[] abDepencies = mainABManifest.GetAllDependencies(abName);
foreach (string depencyAB in abDepencies)
{
if(!abDic.ContainsKey(depencyAB))
{
AssetBundle depency = AssetBundle.LoadFromFile(defaultPath + "/" + depencyAB);
abDic.Add(depencyAB, depency);
}
}
}
catch(UnityException e)
{
Debug.LogError("AB包加载出错");
}
}
public T LoadRes<T>(string abName,string resName) where T : Object
{
LoadAB(abName);
if (abDic.ContainsKey(abName))
{
T res = abDic[abName].LoadAsset<T>(resName);
return res;
}
else
{
return null;
}
}
public Object LoadRes(string abName,string resName,System.Type type)
{
LoadAB(abName);
if (abDic.ContainsKey(abName))
{
Object res = abDic[abName].LoadAsset(resName,type);
return res;
}
else
{
return null;
}
}
#endregion
#region 异步加载
bool isRunning = false;
private Queue<IEnumerator> coroutineQueue = new Queue<IEnumerator>();
public void LoadResAsync<T>(string abName,string resName,UnityAction<T> callBack) where T: Object
{
if (!isRunning)
StartCoroutine(loadResAsync<T>(abName, resName, callBack));
else
coroutineQueue.Enqueue(loadResAsync<T>(abName, resName, callBack));
}
public void LoadResAsync(string abName, string resName,System.Type type,UnityAction<Object> callBack)
{
if(!isRunning)
StartCoroutine(loadResAsync(abName, resName,type,callBack));
else
coroutineQueue.Enqueue(loadResAsync(abName, resName, type, callBack));
}
IEnumerator loadABAsync(string abName)
{
if(abDic.ContainsKey(abName)) yield break;
AssetBundleCreateRequest abcr = AssetBundle.LoadFromFileAsync(defaultPath + "/" + abName);
yield return abcr;
abDic.Add(abName, abcr.assetBundle);
//异步加载其所依赖的包
string[] abDepencies = mainABManifest.GetAllDependencies(abName);
foreach (string depencyAB in abDepencies)
{
if (!abDic.ContainsKey(depencyAB))
{
AssetBundleCreateRequest abcrDepency = AssetBundle.LoadFromFileAsync(defaultPath + "/" + depencyAB);
yield return abcrDepency;
abDic.Add(depencyAB, abcrDepency.assetBundle);
}
}
}
IEnumerator loadResAsync<T>(string abName,string resName,UnityAction<T> callBack) where T: Object
{
isRunning=true;
yield return loadABAsync(abName);
if (abDic.ContainsKey(abName))
{
AssetBundleRequest abr = abDic[abName].LoadAssetAsync<T>(resName);
yield return abr;
callBack(abr.asset as T);
}
else
{
Debug.LogError("AB包加载出错");
}
if (coroutineQueue.Count > 0)
{
yield return StartCoroutine(coroutineQueue.Dequeue());
}
isRunning = false;
}
IEnumerator loadResAsync(string abName,string resName,System.Type type,UnityAction<Object> callBack)
{
isRunning = true;
yield return loadABAsync(abName);
if (abDic.ContainsKey(abName))
{
AssetBundleRequest abr = abDic[abName].LoadAssetAsync(resName,type);
yield return abr;
callBack(abr.asset);
}
else
{
Debug.LogError("AB包加载出错");
}
if (coroutineQueue.Count > 0)
{
yield return StartCoroutine(coroutineQueue.Dequeue());
}
isRunning = false;
}
#endregion
#region 卸载
public void UnLoad(string abName,bool clearResource=false)
{
if (abDic.ContainsKey(abName))
{
abDic[abName].Unload(clearResource);
abDic.Remove(abName);
}
}
public void UnLoadALL(bool clearResources=false)
{
AssetBundle.UnloadAllAssetBundles(clearResources);
abDic.Clear();
}
#endregion
#endregion
}
(简单测试了一下没什么问题。因为我也是菜鸡可能有考虑不到的地方,如果大家测试出了问题,可以跟我说哦。)
396

被折叠的 条评论
为什么被折叠?



