1.简介
AB包(AssetBundle)是Unity中用于资源管理的一种机制,它允许开发者将多个文件(如纹理、模型、音频等)打包成一个单独的文件,以便于在游戏运行时动态加载和卸载。 但是现在出现了最新的Addressable来代替AssetBundle.
Addressables是Unity提供的一个资源管理系统,它是对AssetBundle系统的一种改进和扩展。Addressables允许开发者通过地址(名称或标签)来请求资源,而不是直接操作AssetBundle文件。这使得资源的管理和加载变得更加简单和灵活。现在目前只接收AssetBundle的用法个管理器的代码
2.特点
-
资源优化:通过将相关资源打包在一起,可以减少文件数量,简化资源管理。
-
减少启动时间:游戏开始时不需要加载所有资源,只需加载必要的AB包,从而减少启动时间。
-
动态内容更新:可以单独更新AB包中的内容,而不需要重新下载整个游戏。
3.工作流程
AB包的基本工作流程包括以下几个步骤:
- 构建AB包:在Unity编辑器中,将需要打包的资源分配到相应的AB包中,并设置好它们的名称和变体。
- 打包:使用Unity的构建系统将资源打包成AB包文件。这些文件通常具有
.unity3d
扩展名。我们类自己命名都是可以的 - 加载AB包:在游戏运行时,通过代码动态加载所需的AB包。可以使用
AssetBundle.LoadFromFile
或AssetBundle.LoadFromMemory
等方法。 - 使用资源:从AB包中加载具体的资源,如纹理、预制体等。
- 卸载AB包:当AB包中的资源不再需要时,应该卸载AB包以释放内存。
在使用AB包时,需要注意资源依赖关系的管理,确保在加载资源时,其依赖的所有资源都已正确加载。此外,AB包的版本控制和更新策略也是开发过程中需要考虑的重要方面。
4.AB包管理器
为了管理ab包, 在需要的时候加载ab包, 因此,我们需要建立一个AB包的管理器, 该管理器提供了加载AB包的方式, 为了方便使用者, 可以通过该管理器直接快速加载某AB包里的某个资源.
4.1 效果图和部分说明
以下是AB包加载效果
通过AssetBundleBrowerk可以查看到打的ab包
说明:
- textures.ab包中包含唯一一张贴图, T_Wood.jpg
- materials.ab包中含有两个材质, 分别是M_WineWood和M_Wood, 两个材质都引用的同一张贴图W_Wood.jpg.
- static.ab包中含有两个预制体, wall和floor. wall预制体中的材质是M_Wood, floor中使用的M_WineMood.
依赖关系如下图所示.
其中,在主包中包含3个包, 分别是texture.ab 存放贴图, materials.ab存放材质, static.ab存放预制体. 依赖关系如如下图. 下图中的右图是简化版本. 左图中显示了包与包的依赖关系, 右图展示了贴图-材质-预制体(模型)的关系.
根据AssestBundle的加载资源包(ab包)的规则, 如果你想要加载一个资源包,需要先加载该资源包的依赖包,
如果不先加载依赖包,那么运行的效果可能就是丢失了材质/贴图/脚本或者其他资源导致程序出现异常或者崩溃.
因此, 理清楚依赖关系非常重要. 依赖关系可以在主包中的mainfest文件中获得. 依赖关系就是上图中的线条
所以, 加载顺序为: 加载主包->读取依赖关系->加载依赖包->加载目标包.
在一些很大的游戏中,资源包很大, 因此如果加载资源包等待的时间很长这会导致玩家失去耐心, 和何况在这个短平快的时代. 因此可以根据资源包的大小来进行同步加载
和异步加载
. 同理, 加载完AB包后, 里面的资源可能很大,可能很小, 这需要根据实际来同步加载资源
和异步加载资源
.
以下代码是AB包管理器, 用于加载AB包, 其中也包含了加载资源的同步方式和异步方式. 下图是ABManager.cs
的代码结构.
以下是具体代码:
4.2准备工作
// AB包管理器的目的: 让外部更方便的进行资源加载// 主包:private AssetBundle mainAB = null;// 依赖包获取用的配置文件private AssetBundleManifest manifest = null;// 需要将已加载的AB包存起来, 使用字典存起来// key->ab包的名称 value->包体Dictionary<string, AssetBundle> abDic = new Dictionary<string, AssetBundle>();
4.3 加载AB包的路径以及平台
// 加载包的路径private string PathURL{get {// 可以根据平台不用返回不同的值 streamingAssetsPath 是用于测试// 注意: AssetsBundle打包的时候试注意路径名称和文件夹名称, 因为主包名称会被构建为最后一层的路径名称return Application.streamingAssetsPath + "/" + MainABName + "/";}}// 主包名: 区分不同的平台,Unity根据环境自动区分, 后期根据目标平台构建AB包private string MainABName {get {
#if UNITY_IOSreturn "IOS";
#elif UNITY_ANDROIDreturn "Android"
#elsereturn "PC";
#endif}}
4.4 同步加载AB包
步骤: 加载主包->加载Manifest文件->加载依赖包->加载目标包
使用AssetBundle.LoadFromFile
加载主包/依赖包/目标包,
使用LoadAsset<AssetBundleManifest>("AssetBundleManifest");
加载Mainfest文件获依赖关系
// 同步加载AB包
public AssetBundle LoadAssetBundle(string abName)
{if (abName == ""){Debug.LogError("请输入ab包名称");return null;}// 加载主包 单独保存起来// 加载主包中的关键配置文件, 获取依赖包 单独保存起来// 加载主包和Manifes信息if (mainAB == null){// 路径 + 主包名mainAB = AssetBundle.LoadFromFile(PathURL + MainABName);// 加载包与包之间的依赖文件manifest = mainAB.LoadAsset<AssetBundleManifest>("AssetBundleManifest");}// 获取依赖关系:依赖包AssetBundle ab = null;if (manifest != null){// 遍历mainfest文件, 获取依赖包 获取所有依赖信息string[] dependencies = manifest.GetAllDependencies(abName);for (int i = 0; i < dependencies.Length; ++i){// 如果现有的容器中没有需要加载的包, 则进行加载if (!abDic.ContainsKey(dependencies[i])){// 根据依赖信息加载依赖包 -- 暂时用不上crc循环冗余校验码ab = AssetBundle.LoadFromFile(PathURL + dependencies[i]);// 添加到容器中abDic.Add(dependencies[i], ab);}}}// 加载目标包 加载完依赖包后系统不会自动加载最终我们要的包, 因此需要手动加载if (!abDic.ContainsKey(abName)){ab = AssetBundle.LoadFromFile(PathURL + abName);abDic.Add(abName, ab);}else{ab = abDic[abName];}// 返回资源包return ab;
}
4.5 异步加载资源包
由于异步加载资源包需要配合协程进行操作, 因此在加载资源包的时候需要开启协程. 同时需要注意协程返回数据的时间, 因为每一个包的大小不一样, 因此同时开启多个协程的时候需要注意一些临界值.
public void LoadAssetBundleAsync(string abName, UnityAction<AssetBundle> callback)
{// 开启协程加载AB包StartCoroutine(ReallyLoadAssetBundle(abName, callback));
}
// 协程加载AB包
public IEnumerator ReallyLoadAssetBundle(string abName, UnityAction<AssetBundle> callback)
{if (abName == null || abName == ""){Debug.LogError("加载的AB包不能为空");yield break;}// 先判断是否在abDic中if (abDic.ContainsKey(abName)){yield return abDic[abName]; // 这句可以注释掉callback(abDic[abName]);yield break;}else{// 不在abDic中, 加载主包 和Manifest文件// 加载主包和Manifest信息if (mainAB == null){// 路径 + 主包名AssetBundleCreateRequest abcr = AssetBundle.LoadFromFileAsync(PathURL + MainABName);yield return abcr;mainAB = abcr.assetBundle;// 加载包与包之间的依赖文件AssetBundleRequest abr = mainAB.LoadAssetAsync<AssetBundleManifest>("AssetBundleManifest");yield return abr;manifest = abr.asset as AssetBundleManifest;}// 遍历依赖包string[] dependencies = manifest.GetAllDependencies(abName);// 这里使用队列, 是因为多个协程的返回时间不一样, 如果直接使用abDic.Add的方法会导致异常, 即for循环中的i发生改变,, 因此先用队列缓存起来.// 另外的做法是, 先将名称放入abDic字典中, 值用Null来代替, 加载完毕后再修改abDic中的值Queue<AssetBundle> loadingQueue = new Queue<AssetBundle>(dependencies.Length);for (int i = 0; i < dependencies.Length; i++){// 开启单个依赖包的加载协程StartCoroutine(LoadSingleDependenceAsync(dependencies[i], (temp) =>{// 加载完毕后入队loadingQueue.Enqueue(temp);}));}// 依赖包加载完毕后加载目标包-->开启加载目标包的协程StartCoroutine(LoadTargetAssetBundleAsync(abName, (temp) => {// 等待所有依赖包加载完成// 出队, 添加到abDic中while (loadingQueue.Count > 0){AssetBundle loadedAB = loadingQueue.Dequeue();abDic.Add(loadedAB.name, loadedAB);}callback(temp);}));}
}// 依赖包的加载 : 依赖包名称, 路径, 加载完毕的回调函数
public IEnumerator LoadSingleDependenceAsync(string dependName, UnityAction<AssetBundle> callback)
{AssetBundleCreateRequest abcr = AssetBundle.LoadFromFileAsync(PathURL + dependName);if (abcr.assetBundle != null){yield return abcr;callback(abcr.assetBundle);}else{Debug.LogError("单个依赖包加载出错");callback(null);yield break;}
}// 加载目标包的协程
public IEnumerator LoadTargetAssetBundleAsync(string abName, UnityAction<AssetBundle> callback)
{AssetBundleCreateRequest abcr = AssetBundle.LoadFromFileAsync(PathURL + abName);if (abcr.assetBundle != null){yield return abcr;callback(abcr.assetBundle);}else{Debug.LogError("目标包加载出错");callback(null);yield break;}
}
4.6 同步加载资源的三种方式
/// <summary>
/// 同步加载
/// </summary>
/// <typeparam name="T">通过泛型加载</typeparam>
/// <param name="abName">资源包的名称</param>
/// <param name="resName">资源名称</param>
/// <returns>加载的资源</returns>
public T LoadResources<T>(string abName, string resName) where T : Object
{AssetBundle ab = LoadAssetBundle(abName);if (ab == null){return null;}// Debug.Log("同步加载-指定泛型的加载模式");return ab.LoadAsset<T>(resName);
}// 同步加载 不指定类型
public Object LoadResources(string abName, string resName)
{// 加载AB包AssetBundle ab = LoadAssetBundle(abName);Object obj = ab.LoadAsset(resName);// Debug.Log("同步加载-不指定类型的加载模式");return obj;
}/// <summary>
/// 使用资源类型的方式进行加载 xLua中不支持泛型所以使用type类型
/// </summary>
/// <param name="abName">资源包的名称</param>
/// <param name="resName">资源名称</param>
/// <param name="type">资源类型</param>
/// <returns>加载的资源</returns>
// 同步加载 根据type指定类型 这里使用System.Type是因为返回的对象Object在Unity和System中均有Object.
public Object LoadResources(string abName, string resName, System.Type type)
{// 加载AB包AssetBundle ab = LoadAssetBundle(abName);Object obj = ab.LoadAsset(resName, type);// Debug.Log("同步加载-指定Type的加载模式");return obj;
}
4.7 异步加载资源的三种方式
异步加载AB后, 异步加载包中的资源
/// <summary>
/// 异步加载资源-启动协程
/// </summary>
public void LoadResourcesAsync(string abName, string resName, UnityAction<Object> callback)
{// 开启协程StartCoroutine(ReallyLoadResourcesAsync(abName, resName, callback));
}// 异步加载资源的协程
public IEnumerator ReallyLoadResourcesAsync(string abName, string resName, UnityAction<Object> callback)
{LoadAssetBundleAsync(abName, (tmp) =>{AssetBundleRequest abr = tmp.LoadAssetAsync(resName);if (abr == null || abr.asset == null){Debug.LogError("未能加载资源包");callback(null);}else{callback(abr.asset);}// 得到资源后abr后返回abr的asset});yield return resName;
}/// <summary>
/// 异步加载资源的泛型的方式
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="abName"></param>
/// <param name="resName"></param>
/// <param name="callback"></param>
public void LoadResourcesAsync<T>(string abName, string resName, UnityAction<T> callback) where T : Object
{// 开启协程StartCoroutine(ReallyLoadResourcesAsync<T>(abName, resName, callback));
}// 异步加载资源的协程
public IEnumerator ReallyLoadResourcesAsync<T>(string abName, string resName, UnityAction<T> callback) where T : UnityEngine.Object
{LoadAssetBundleAsync(abName, (tmp) =>{AssetBundleRequest abr = tmp.LoadAssetAsync(resName);if (abr == null || abr.asset == null){Debug.LogError("未能加载资源包");callback(null);}else{callback(abr.asset as T);}// 得到资源后abr后返回abr的asset});yield return null;
}public void LoadResourcesAsync(string abName, string resName, System.Type type, UnityAction<Object> callback)
{// 开启协程StartCoroutine(ReallyLoadResourcesAsync(abName, resName, type, callback));
}// 异步加载资源的协程
public IEnumerator ReallyLoadResourcesAsync(string abName, string resName, System.Type type, UnityAction<Object> callback)
{this.LoadAssetBundleAsync(abName, (tmp) =>{AssetBundleRequest abr = tmp.LoadAssetAsync(resName, type);if (abr == null || abr.asset == null){Debug.LogError("未能加载资源包");callback(null);}else{callback(abr.asset);}// 得到资源后abr后返回abr的asset});yield return null;
}
4.8 AB包卸载
// 单个包的卸载
public void UnloadRes(string abName)
{ if (abDic.ContainsKey(abName)){abDic[abName].Unload(false);abDic.Remove(abName);}
}// 所有包的卸载
public void ClearAB()
{AssetBundle.UnloadAllAssetBundles(false);abDic.Clear();mainAB = null;manifest = null;
}
4.9 完整代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;public class ABManager : SingletonAutoMono<ABManager>
{// AB包管理器的目的: 让外部更方便的进行资源加载// 主包:private AssetBundle mainAB = null;// 依赖包获取用的配置文件private AssetBundleManifest manifest = null;// 加载分为同步加载异步加载// AB包加载的特点: 加载后不能再次加载, 因此, 如果作为AB包加载卸载管理器的话// 需要将已加载的AB包存起来, 使用字典存起来// key-> ab包的名称 value->包体Dictionary<string, AssetBundle> abDic = new Dictionary<string, AssetBundle>();#region 加载AB包的路径以及平台// 加载包的路径private string PathURL{get {// 可以根据平台不用返回不同的值 streamingAssetsPath 是用于测试// 注意: AssetsBundle打包的时候试注意路径名称和文件夹名称, 应为主包名称会被构建为最后一层的路径名称return Application.streamingAssetsPath + "/" + MainABName + "/";}}// 主包名: 区分不同的平台private string MainABName {get {
#if UNITY_IOSreturn "IOS";
#elif UNITY_ANDROIDreturn "Android"
#elsereturn "PC";
#endif}}
#endregion#region 同步加载AB包// 同步加载以及同步加载的方法public AssetBundle LoadAssetBundle(string abName){if(abName == ""){Debug.LogError("请输入ab包名称");return null;}// 加载主包 单独保存起来// 加载主包中的关键配置文件, 获取依赖包 单独保存起来// 加载主包和Manifes信息if (mainAB == null){// 路径 + 主包名mainAB = AssetBundle.LoadFromFile(PathURL + MainABName);// 加载包与包之间的依赖文件manifest = mainAB.LoadAsset<AssetBundleManifest>("AssetBundleManifest");}// 获取依赖关系:依赖包AssetBundle ab = null;if (manifest != null){// 遍历mainfest文件, 获取依赖包 获取所有依赖信息string[] dependencies = manifest.GetAllDependencies(abName);for (int i = 0; i < dependencies.Length; ++i){// 如果现有的容器中没有需要加载的包, 则进行加载if(!abDic.ContainsKey(dependencies[i])){// 根据依赖信息加载依赖包 -- 暂时用不上crc循环冗余校验码ab = AssetBundle.LoadFromFile(PathURL + dependencies[i]);// 添加到容器中abDic.Add(dependencies[i], ab);}}}// 加载资源来源包if(!abDic.ContainsKey(abName)){ab = AssetBundle.LoadFromFile(PathURL + abName);abDic.Add(abName, ab);}else{ab = abDic[abName];}// 返回资源包return ab;}#endregion#region 异步加载AB包public void LoadAssetBundleAsync(string abName, UnityAction<AssetBundle> callback){// 使用协程加载AB包StartCoroutine(ReallyLoadAssetBundle(abName, callback));}public IEnumerator ReallyLoadAssetBundle(string abName, UnityAction<AssetBundle> callback){if(abName == null || abName == ""){Debug.LogError("加载的AB包不能为空");yield break;}// 先判断是否在abDic中if(abDic.ContainsKey(abName)){yield return abDic[abName];callback(abDic[abName]);yield break;}else{// 不在abDic中, 加载主包 和Manifest文件// 加载主包和Manifest信息if (mainAB == null){// 路径 + 主包名AssetBundleCreateRequest abcr = AssetBundle.LoadFromFileAsync (PathURL + MainABName);yield return abcr;mainAB = abcr.assetBundle;// 加载包与包之间的依赖文件AssetBundleRequest abr = mainAB.LoadAssetAsync<AssetBundleManifest>("AssetBundleManifest");yield return abr;manifest = abr.asset as AssetBundleManifest;}// 遍历依赖包// AssetBundle singleAssetBundle;string[] dependencies = manifest.GetAllDependencies(abName);// 这里使用队列作为缓存是为了防止直接使用abDic.Add添加异常// 如果直接使用abDic.Add会导致下标异常// 原因是 多个协程加载资源的返回的先后顺序不一致导致for循环导致i值变化, 从而导致abDic的异常// 另外一种办法是将资源包的name先添加到abDic的key中, value用null占位, 然后在将加载好的资源包放入到abDic的gvalue中Queue<AssetBundle> loadingQueue = new Queue<AssetBundle>(dependencies.Length);for (int i = 0; i < dependencies.Length; i++){// 开启单个依赖包的加载协程StartCoroutine(LoadSingleDependenceAsync(dependencies[i], (temp) =>{//singleAssetBundle = temp;//Debug.Log(singleAssetBundle.name);loadingQueue.Enqueue(temp);// 添加到字典中去//abDic.Add(dependencies[i], singleAssetBundle);})); }// 依赖包加载完毕后加载目标包StartCoroutine(LoadTargetAssetBundleAsync(abName, (temp) => {// singleAssetBundle = temp;// 等待所有依赖包加载完成while (loadingQueue.Count > 0){AssetBundle loadedAB = loadingQueue.Dequeue();abDic.Add(loadedAB.name, loadedAB);}// abDic.Add(abName, singleAssetBundle);callback(temp);}));}}// 依赖包的加载 : 依赖包名称, 路径, 加载完毕的回调函数public IEnumerator LoadSingleDependenceAsync(string dependName, UnityAction<AssetBundle> callback){AssetBundleCreateRequest abcr = AssetBundle.LoadFromFileAsync(PathURL + dependName);if(abcr.assetBundle != null){yield return abcr;callback(abcr.assetBundle);}else{Debug.LogError("单个依赖包加载出错");callback(null);yield break;} }// 加载目标包public IEnumerator LoadTargetAssetBundleAsync(string abName, UnityAction<AssetBundle> callback){AssetBundleCreateRequest abcr = AssetBundle.LoadFromFileAsync(PathURL + abName);if (abcr.assetBundle != null){yield return abcr;callback(abcr.assetBundle);}else{Debug.LogError("目标包加载出错");callback(null);yield break;}}#endregion#region 使用泛型方式同步加载资源/// <summary>/// 同步加载/// </summary>/// <typeparam name="T">通过类型加载</typeparam>/// <param name="abName">资源包的名称</param>/// <param name="resName">资源类型</param>/// <returns></returns>public T LoadResources<T>(string abName, string resName) where T : Object{AssetBundle ab = LoadAssetBundle( abName);if(ab == null){return null;}// Debug.Log("同步加载-指定泛型的加载模式");return ab.LoadAsset<T>(resName);}#endregion#region 普通方式同步加载资源//同步加载 不指定类型public Object LoadResources(string abName, string resName){//加载AB包AssetBundle ab = LoadAssetBundle(abName);Object obj = ab.LoadAsset(resName);// Debug.Log("同步加载-不指定类型的加载模式");return obj;}#endregion#region 使用type方式同步加载资源/// <summary>/// 使用资源类型的方式进行加载 xLua中不支持泛型所以使用type类型/// </summary>/// <param name="abName"></param>/// <param name="resName"></param>/// <param name="type"></param>/// <returns></returns>//同步加载 根据type指定类型 这里使用System.Type是因为返回的对象Object在Unity和System中均有Object.public Object LoadResources(string abName, string resName, System.Type type){//加载AB包AssetBundle ab = LoadAssetBundle(abName);Object obj = ab.LoadAsset(resName, type);//Debug.Log("同步加载-指定Type的加载模式");return obj;}#endregion#region 使用异步加载资源/// <summary>/// 异步加载资源-启动协程/// </summary>public void LoadResourcesAsync(string abName, string resName, UnityAction<Object> callback){// 开启协程StartCoroutine(ReallyLoadResourcesAsync(abName, resName, callback));}// 异步加载资源的协程public IEnumerator ReallyLoadResourcesAsync(string abName, string resName, UnityAction<Object> callback){LoadAssetBundleAsync(abName, (tmp)=>{AssetBundleRequest abr = tmp.LoadAssetAsync(resName);if (abr == null || abr.asset == null){Debug.LogError("未能加载资源包");callback(null);}else{callback(abr.asset);}// 得到资源后abr后返回abr的asset});yield return resName; }#endregion#region 使用异步泛型加载资源/// <summary>/// 异步加载资源的泛型的方式/// </summary>/// <typeparam name="T"></typeparam>/// <param name="abName"></param>/// <param name="resName"></param>/// <param name="callback"></param>public void LoadResourcesAsync<T>(string abName, string resName, UnityAction<T> callback) where T : Object{// 开启协程StartCoroutine(ReallyLoadResourcesAsync<T>(abName, resName, callback));}// 异步加载资源的协程public IEnumerator ReallyLoadResourcesAsync<T>(string abName, string resName, UnityAction<T> callback) where T : UnityEngine.Object{LoadAssetBundleAsync(abName, (tmp) =>{AssetBundleRequest abr = tmp.LoadAssetAsync(resName);if (abr == null || abr.asset == null){Debug.LogError("未能加载资源包");callback(null);}else{callback(abr.asset as T);}// 得到资源后abr后返回abr的asset});yield return null;}#endregion#region 使用异步Type加载资源public void LoadResourcesAsync(string abName, string resName, System.Type type, UnityAction<Object> callback){// 开启协程StartCoroutine(ReallyLoadResourcesAsync(abName, resName, callback));}// 异步加载资源的协程public IEnumerator ReallyLoadResourcesAsync(string abName, string resName, System.Type type, UnityAction<Object> callback){this.LoadAssetBundleAsync(abName, (tmp) =>{AssetBundleRequest abr = tmp.LoadAssetAsync(resName, type);if (abr == null || abr.asset == null){Debug.LogError("未能加载资源包");callback(null);}else{callback(abr.asset);}// 得到资源后abr后返回abr的asset});yield return null;}#endregion#region 卸载AB包// 单个包的卸载public void UnloadRes(string abName){ if(abDic.ContainsKey(abName)){abDic[abName].Unload(false);abDic.Remove(abName);}}// 所有包的卸载public void ClearAB(){AssetBundle.UnloadAllAssetBundles(false);abDic.Clear();mainAB = null;manifest = null;}#endregion
}
5.测试代码
以下是AB包管理器的测试代码, 分为部分小节, 测试的结果是最开始的图片上的效果.
5.1 相关变量和函数
// 同步加载测试private GameObject cube1;private GameObject cube2;private GameObject cube3;private GameObject floor1;// 同步加载测试根节点private GameObject root1;// 异步加载测试private GameObject cube4;private GameObject cube5;private GameObject cube6;private GameObject floor2;// 异步加载测试根节点private GameObject root2;
// 初始化根节点以便作为区分
private void InitRoot()
{root1 = new GameObject();root2 = new GameObject();root1.name = "同步加载Root";root2.name = "异步加载Root";
}
5.2 同步加载测试
public void TestLoadResourceAndPackage()
{// 同步加载测试--Typecube1 = ABManager.GetInstance().LoadResources("static.ab", "wall", typeof(GameObject)) as GameObject;cube1 = Instantiate(cube1);cube1.name = "同步--Type";cube1.transform.position = Vector3.one * -2;cube1.transform.SetParent(root1.transform);// 同步加载测试--泛型cube2 = ABManager.GetInstance().LoadResources<GameObject>("static.ab", "wall");cube2 = Instantiate(cube2);cube2.name = "同步--T泛型";cube2.transform.position = Vector3.one * -1;cube2.transform.SetParent(root1.transform);// 同步加载测试floor1 = ABManager.GetInstance().LoadResources("static.ab", "floor") as GameObject;floor1 = Instantiate(floor1);floor1.name = "同步--Normal";floor1.transform.position = Vector3.zero;floor1.transform.SetParent(root1.transform);
}
5.3异步加载测试
public void TestLoadResourceAndPackAsync()
{// 异步加载测试--只测试包的加载ABManager.GetInstance().LoadAssetBundleAsync("static.ab", LoadABAsync);// 异步加载测试ABManager.GetInstance().LoadResourcesAsync("static.ab", "wall", LoadResAndPackAsyncNormal);// 异步加载测试--泛型ABManager.GetInstance().LoadResourcesAsync<GameObject>("static.ab", "wall", LoadResAndPackAsyncT);// 异步加载测试--TypeABManager.GetInstance().LoadResourcesAsync("static.ab", "wall", typeof(GameObject), LoadResAndPackAsyncType);
}// 异步测试AB包
private void LoadABAsync(AssetBundle ab)
{Debug.Log("测试异步加载只加载资源包的情况, 加载的包名" + ab.name);
}// 测试异步加载资源-normal
private void LoadResAndPackAsyncNormal(UnityEngine.Object obj)
{cube4 = Instantiate(obj as GameObject);cube4.name = "异步--normal";cube4.transform.position = Vector3.one;cube4.transform.SetParent(root2.transform);
}// 测试异步加载资源-T泛型
private void LoadResAndPackAsyncT(GameObject obj)
{cube5 = Instantiate(obj);cube5.name = "异步--T泛型";cube5.transform.position = Vector3.one * 2;cube5.transform.SetParent(root2.transform);
}// 测试异步加载资源-Type
private void LoadResAndPackAsyncType(UnityEngine.Object obj)
{cube6 = Instantiate(obj as GameObject);cube6.name = "异步--Type";cube6.transform.position = Vector3.one * 3;cube6.transform.SetParent(root2.transform);
}
5.4 完整的测试代码
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class TestABManager : MonoBehaviour
{// 同步加载测试private GameObject cube1;private GameObject cube2;private GameObject cube3;private GameObject floor1;// 同步加载测试根节点private GameObject root1;// 异步加载测试private GameObject cube4;private GameObject cube5;private GameObject cube6;private GameObject floor2;// 异步加载测试根节点private GameObject root2;void Start(){InitRoot();TestLoadResourceAndpackage();TestLoadResourceAndPackAsync();}private void InitRoot(){root1 = new GameObject();root2 = new GameObject();root1.name = "同步加载Root";root2.name = "异步加载Root";}// 测试同步加载方式public void TestLoadResourceAndpackage(){// 同步加载测试--Typecube1 = ABManager.GetInstance().LoadResources("static.ab", "wall", typeof(GameObject)) as GameObject;cube1 = Instantiate(cube1);cube1.name = "同步--Type";cube1.transform.position = Vector3.one * -2;cube1.transform.SetParent(root1.transform);// 同步加载测试--泛型cube2 = ABManager.GetInstance().LoadResources<GameObject>("static.ab", "wall");cube2 = Instantiate(cube2);cube2.name = "同步--T泛型";cube2.transform.position = Vector3.one * -1;cube2.transform.SetParent(root1.transform);// 同步加载测试floor1 = ABManager.GetInstance().LoadResources("static.ab", "floor") as GameObject;floor1 = Instantiate(floor1);floor1.name = "同步--Normal";floor1.transform.position = Vector3.zero;floor1.transform.SetParent(root1.transform);}// 测试异步加载方式public void TestLoadResourceAndPackAsync(){// 异步加载测试--只测试包的加载ABManager.GetInstance().LoadAssetBundleAsync("static.ab",LoadABAsync);// 异步加载测试ABManager.GetInstance().LoadResourcesAsync("static.ab", "wall", LoadResAndPackAsyncNormal);// 异步加载测试--泛型ABManager.GetInstance().LoadResourcesAsync<GameObject>("static.ab", "wall", LoadResAndPackAsyncT);// 异步加载测试--TypeABManager.GetInstance().LoadResourcesAsync("static.ab", "wall", typeof(GameObject), LoadResAndPackAsyncType);}// 异步测试AB包private void LoadABAsync(AssetBundle ab){Debug.Log("测试异步加载只加载资源包的情况, 加载的包名" + ab.name);}// 测试异步加载资源-normalprivate void LoadResAndPackAsyncNormal(UnityEngine.Object obj){cube4 = Instantiate(obj as GameObject);cube4.name = "异步--normal";cube4.transform.position = Vector3.one;cube4.transform.SetParent(root2.transform);}// 测试异步加载资源-T泛型private void LoadResAndPackAsyncT(GameObject obj){cube5 = Instantiate(obj);cube5.name = "异步--T泛型";cube5.transform.position = Vector3.one * 2;cube5.transform.SetParent(root2.transform);}// 测试异步加载资源-Typeprivate void LoadResAndPackAsyncType(UnityEngine.Object obj){cube6 = Instantiate(obj as GameObject);cube6.name = "异步--Type";cube6.transform.position = Vector3.one * 3;cube6.transform.SetParent(root2.transform);}}