注意:考虑到热更新的内容比较多,我将热更新的内容分开,并全部整合放在【unity游戏开发——热更新】专栏里,感兴趣的小伙伴可以前往逐一查看学习。
文章目录
前言1、什么是AssetBundle?2、AB包与Resources系统对比3、AB包核心价值
一、AB包打包工具Asset Bundle Browser1、下载安装AssetBundles-Browser2、打开Asset Bundle Browser窗口3、如何让资源关联AB包
二、AssetBundleBrowser参数相关1、Configure 配置页签2、Build 构建页签2.1 参数(1)BuildTarget: 目标平台(2)Output Path: 目标输出路径(3)Clear Folders:重新打包时是否清空目标路径的文件夹(4)Copy To StreamingAssets(5)Compression 压缩方式(6)Exclude Type Information(7)Force Rebuild(8)Ignore Type Tree Changes(9)Append Hash(10)Strict Mode(11)Dry Run Build(12)Build打包按钮
2.2 实战
3、Inspect 检查页签
三、代码加载AB包和AB包中的资源1、同步加载AB包和AB包中的资源1.1 AssetBundle.LoadFromFile同步地从指定路径加载AB包,返回加载后的AB包。1.2 AssetBundle.LoadAsset 同步的从一个已加载的AB包中加载指定资源1.3 同一个AB包可以用于加载多个不同资源
2、异步加载AB包和AB包中的资源2.1 AssetBundle.LoadFromFileAsync 异步地从指定路径加载AB包,返回异步加载AB包的类2.2 AssetBundle.LoadAssetAsync 异步地从一个已加载的AB包中加载指定资源2.3 调用协程进行异步加载2.4 示例2.5 AB包不能加载两次
3、卸载AB包和AB包中的资源3.1 AssetBundle.Unload 卸载指定的AB包3.2 AssetBundle.UnloadAllAssetBundles 卸载所有已加载的AB包
四、AB包的依赖包1、手动加载AB包的依赖包2、通过主AB包的依赖关系清单文件加载AB包的依赖包
五、封装AB包资源管理器1、继承MonoBehaviour的泛型单例模式基类2、封装AssetBundle管理器3、调用测试
六、总结专栏推荐完结
前言
1、什么是AssetBundle?
AssetBundle 是 Unity 中的一种资源打包格式,用于将游戏资源(如模型、纹理、音频等)分块压缩,便于动态加载和更新。开发者可以将资源按需打包成多个 AssetBundle,运行时通过网络下载或本地加载,减少初始包体大小,支持热更新和资源管理优化。
特定平台的资源容器:针对不同平台(Windows/Android/iOS等)优化的资源压缩包资源集合:包含模型、贴图、材质、预设体、音频等资源,不包含C#代码灵活部署:可存储在任意位置(本地或远程服务器)
2、AB包与Resources系统对比
特性Resources系统AssetBundle系统资源位置必须放在Resources文件夹任意位置资源管理单个资源加载资源集合打包更新能力只读,无法更新支持动态更新包体大小增加初始包体减小初始包体热更新不支持支持资源/脚本热更新内存管理较差精细控制
3、AB包核心价值
减小初始包体:压缩资源,按需下载
热更新能力:更新资源/Lua脚本无需重新发布应用
资源管理优化:替代Resources系统,避免"资源地狱"
跨平台支持:自动适配不同平台格式
一、AB包打包工具Asset Bundle Browser
1、下载安装AssetBundles-Browser
官方提供好的打包工具:Asset Bundle Browser
注意:对于高版本Unity中,已经不能通过包管理器进行下载。原因是高版本Unity出现了Addressables已经封装了AB包功能(后面我们会单独学习它),目前实际项目已经很少会使用Asset Bundle Browser来进行开发了,不过这里我还是推荐先通过Asset Bundle Browser来进行AssetBundle的学习,因为只有通过对比,你才能更能理解新技术带来的优势。
可以在github下载AssetBundles-Browser压缩包:https://github.com/Unity-Technologies/AssetBundles-Browser
把AssetBundles-Browser插件包解压缩导入你的工程中。
若你像我一样导入后报错,只需删除示例文件夹(也就是Test文件夹)即可
2、打开Asset Bundle Browser窗口
3、如何让资源关联AB包
创建一个cube预制体
在预制体下方新建AB包model并选择。
就能在AB包窗口看到我们新建的AB包和资源。(注意:假如没刷出来,可以点击左上角的刷新按钮) 多选一些图片资源,同时放到一个新创建的icon包。 点击刷新,也能在AB包正常显示 注意:C#代码不能放到AB包,因为C#是编译型语言,我们才需要脚本语言lua(如果你了解过热更知识应该听说过lua)。而预制体实际上是一堆数据组成的,记录了关联的脚本,预制体上的脚本并不会打进AB包,打进AB包的是预制体数据。
二、AssetBundleBrowser参数相关
1、Configure 配置页签
可以查看项目中的AB包其中的资源
2、Build 构建页签
2.1 参数
(1)BuildTarget: 目标平台
常用的平台有Window、Ios、Android不同平台要重新打包
(2)Output Path: 目标输出路径
(3)Clear Folders:重新打包时是否清空目标路径的文件夹
(4)Copy To StreamingAssets
是否把打包到目标路径的AB包拷贝一份到StreamingAssets文件夹,对StreamingAssets文件夹不了解的可以参考:Application和unity特殊文件夹
(5)Compression 压缩方式
NoCompression:不压缩,解压快,包较大(不推荐)LZMA:压缩最小,解压慢 缺点:如果要用AB包中的一个资源,要解压整个AB包LZ4:压缩,相对LZMA大一点点 建议使用什么AB包中的什么资源就解压什么资源,内存占用低
(6)Exclude Type Information
在AB资源包中 不包含资源的类型信息 不建议勾选
(7)Force Rebuild
重新打包时需要重新构建包 和ClearFolders不同 它不会删除不再存在的包 不建议勾选 勾选Clear Folders就好
(8)Ignore Type Tree Changes
增量构建检查时,忽略类型树的更改,不建议勾选
(9)Append Hash
将文件哈希值附加到资源包名上
(10)Strict Mode
严格模式,如果打包时报错了,则打包直接失败无法成功 建议启用
(11)Dry Run Build
运行时构建 建议使用
(12)Build打包按钮
2.2 实战
点击打包后 因为选择了清空目标路径的文件夹和拷贝到StreamingAssets,可能会弹出是否希望删除目标路径和StreamingAssets的所有文件,点击Yes即可。
打包成功后会在Asset同级目录生成填好的目标路径
在AB包生成的文件中 StandaloneWindows包是我们的主包(和目录名一样的包),StandaloneWindows存储了很多关键信息和依赖关系等,model和icon才算我们真正打包出去的AB包其中没有后缀的文件是我们的资源文件,.manifest后缀的文件是记录资源文件资源信息、依赖关系、版本信息等等的文件 打包成功后,假如StreamingAssets没有刷新拷贝的AB包,尝试右键或者快捷键ctrl+R手动刷新
3、Inspect 检查页签
可以点击添加AB包资源文件或者文件夹 查看AB包的具体信息
三、代码加载AB包和AB包中的资源
1、同步加载AB包和AB包中的资源
1.1 AssetBundle.LoadFromFile同步地从指定路径加载AB包,返回加载后的AB包。
//由于我们选择了StreamingAssets中多拷贝一份 可以直接从StreamingAssets加载AB包
AssetBundle modelAssetBundle = AssetBundle.LoadFromFile(Application.streamingAssetsPath + "/" + "model");
注意: 同一个AB包不能加载两次 否则报错: The AssetBundle 'model' can't be loaded because another AssetBundle with the same files is already loaded.
1.2 AssetBundle.LoadAsset 同步的从一个已加载的AB包中加载指定资源
//假如只传名字可能会得到同名不同类型的资源 不建议使用
GameObject cube = modelAssetBundle.LoadAsset("Cube") as GameObject;
//泛型加载 纯C#项推荐 但是Lua中不支持
GameObject cube = modelAssetBundle.LoadAsset
//传入资源的Type 要as成实际类型 Lua中支持
GameObject cube = modelAssetBundle.LoadAsset("Cube", typeof(GameObject)) as GameObject;
1.3 同一个AB包可以用于加载多个不同资源
using UnityEngine;
public class LoadAB : MonoBehaviour {
void Start()
{
//由于我们选择了StreamingAssets中多拷贝一份 可以直接从StreamingAssets加载AB包
AssetBundle modelAssetBundle = AssetBundle.LoadFromFile(Application.streamingAssetsPath + "/" + "model");
GameObject cube = modelAssetBundle.LoadAsset("Cube", typeof(GameObject)) as GameObject;
Instantiate(cube);//实例化
//同一个AB包可以用于加载多个不同资源
GameObject sphere = modelAssetBundle.LoadAsset("Sphere", typeof(GameObject)) as GameObject;
Instantiate(sphere);//实例化
}
}
效果
2、异步加载AB包和AB包中的资源
2.1 AssetBundle.LoadFromFileAsync 异步地从指定路径加载AB包,返回异步加载AB包的类
IEnumerator LoadAssetBundleAsync
{
AssetBundleCreateRequest assetBundleCreateRequest = AssetBundle.LoadFromFileAsync(Application.streamingAssetsPath + "/" + AssetBundleName);
yield return assetBundleCreateRequest;//等待AB包加载完成
}
2.2 AssetBundle.LoadAssetAsync 异步地从一个已加载的AB包中加载指定资源
///
/// 异步加载AB包中的资源
///
///
/// AB包名
/// 资源名称
/// 回调函数
IEnumerator LoadAssetBundleAsync
{
//异步地从指定路径加载AB包,返回异步加载AB包的类
AssetBundleCreateRequest assetBundleCreateRequest = AssetBundle.LoadFromFileAsync(Application.streamingAssetsPath + "/" + AssetBundleName);
yield return assetBundleCreateRequest;//等待AB包加载完成
//和同步加载类似 异步加载也有三个重载
//假如只传名字可能会得到同名不同类型的资源 不建议使用
//AssetBundleRequest assetBundleRequest = assetBundleCreateRequest.assetBundle.LoadAssetAsync(resourceName);
//泛型加载 纯C#项推荐 但是Lua中不支持
//AssetBundleRequest assetBundleRequest = assetBundleCreateRequest.assetBundle.LoadAssetAsync
//传入资源的Type
AssetBundleRequest assetBundleRequest = assetBundleCreateRequest.assetBundle.LoadAssetAsync(resourceName, typeof(T));
yield return assetBundleRequest;//等待资源加载完成
//异步加载AB包中的资源的类中的asset属性代表实际加载出的资源 要转换成实际的类型
T loadedAsset = (T)assetBundleRequest.asset;
callback?.Invoke(loadedAsset); // 通过回调返回结果
}
2.3 调用协程进行异步加载
//开启协程
StartCoroutine(LoadAssetBundleAsync
{
//操作
}));
2.4 示例
using System;
using System.Collections;
using UnityEngine;
using UnityEngine.UI;
public class LoadAB : MonoBehaviour
{
public Image image;
void Start()
{
//开启协程
StartCoroutine(LoadAssetBundleAsync
{
image.sprite = result; //加载出来的资源赋值给Image
}));
}
///
/// 异步加载AB包中的资源
///
///
/// AB包名
/// 资源名称
/// 回调函数
IEnumerator LoadAssetBundleAsync
{
//异步地从指定路径加载AB包,返回异步加载AB包的类
AssetBundleCreateRequest assetBundleCreateRequest = AssetBundle.LoadFromFileAsync(Application.streamingAssetsPath + "/" + AssetBundleName);
yield return assetBundleCreateRequest;//等待AB包加载完成
//异步地从一个已加载的AB包中加载指定资源
AssetBundleRequest assetBundleRequest = assetBundleCreateRequest.assetBundle.LoadAssetAsync(resourceName, typeof(T));
yield return assetBundleRequest;//等待资源加载完成
//异步加载AB包中的资源的类中的asset属性代表实际加载出的资源 要转换成实际的类型
T loadedAsset = (T)assetBundleRequest.asset;
callback?.Invoke(loadedAsset); // 通过回调返回结果
}
}
注意图片要设置成单一Sprite纹理类型,修改后记得重新打成AB包 运行结果,可以看到图片被渲染出来了
2.5 AB包不能加载两次
注意: 和前面一样,同一个AB包不能加载两次 否则报错: The AssetBundle 'icon' can't be loaded because another AssetBundle with the same files is already loaded.
using System;
using System.Collections;
using UnityEngine;
using UnityEngine.UI;
public class LoadAB : MonoBehaviour
{
public Image image;
public Image image2;
void Start()
{
//开启协程
StartCoroutine(LoadAssetBundleAsync
{
image.sprite = result; //加载出来的资源赋值给Image
}));
StartCoroutine(LoadAssetBundleAsync
{
image2.sprite = result; //加载出来的资源赋值给Image
}));
}
///
/// 异步加载AB包中的资源
///
///
/// AB包名
/// 资源名称
/// 回调函数
IEnumerator LoadAssetBundleAsync
{
//异步地从指定路径加载AB包,返回异步加载AB包的类
AssetBundleCreateRequest assetBundleCreateRequest = AssetBundle.LoadFromFileAsync(Application.streamingAssetsPath + "/" + AssetBundleName);
yield return assetBundleCreateRequest;//等待AB包加载完成
//异步地从一个已加载的AB包中加载指定资源
AssetBundleRequest assetBundleRequest = assetBundleCreateRequest.assetBundle.LoadAssetAsync(resourceName, typeof(T));
yield return assetBundleRequest;//等待资源加载完成
//异步加载AB包中的资源的类中的asset属性代表实际加载出的资源 要转换成实际的类型
T loadedAsset = (T)assetBundleRequest.asset;
callback?.Invoke(loadedAsset); // 通过回调返回结果
}
}
结果,报错了
3、卸载AB包和AB包中的资源
3.1 AssetBundle.Unload 卸载指定的AB包
传入的参数是是否卸载场景上加载出来的AB包资源
modelAssetBundle.Unload(false);
3.2 AssetBundle.UnloadAllAssetBundles 卸载所有已加载的AB包
传入的参数是是否卸载场景上加载出来的AB包资源。
AssetBundle.UnloadAllAssetBundles(false);
四、AB包的依赖包
1、手动加载AB包的依赖包
创建红色材质球。 将这个材质设置到cube上
注意:前面的材质球我们并没有选择打成AB包。但是在AB包窗口中可以看到model包自动依赖了红色材质球。 我们可以写代码,使用AB包同步加载这个cube出来看看效果(记得改了材质球,需要Bulid重新打AB包)
using UnityEngine;
public class LoadAB : MonoBehaviour
{
void Start()
{
AssetBundle modelAssetBundle = AssetBundle.LoadFromFile(Application.streamingAssetsPath + "/" + "model");
GameObject cube = modelAssetBundle.LoadAsset("Cube", typeof(GameObject)) as GameObject;
Instantiate(cube);//实例化
}
}
效果 但是假如把红色材质球放到了icon包,那么就不会自动依赖到model包 点击重新生成AB包后,使用AB包同步加载cube,由于model包没有cube需要的材质,材质所在的icon包没有被加载。加载出来的cube会丢失材质,显示粉色。 我们加载红色材质球所在的icon包,cube就能正常显示了
using UnityEngine;
public class LoadAB : MonoBehaviour
{
//在游戏开始时调用
void Start()
{
//加载AssetBundle文件
AssetBundle modelAssetBundle = AssetBundle.LoadFromFile(Application.streamingAssetsPath + "/" + "model");
//从AssetBundle中加载名为Cube的GameObject
GameObject cube = modelAssetBundle.LoadAsset("Cube", typeof(GameObject)) as GameObject;
//实例化GameObject
Instantiate(cube);//实例化
//加载icon依赖包
AssetBundle iconlAssetBundle = AssetBundle.LoadFromFile(Application.streamingAssetsPath + "/" + "icon");
}
}
效果
2、通过主AB包的依赖关系清单文件加载AB包的依赖包
using UnityEngine;
public class LoadAB : MonoBehaviour
{
//在游戏开始时调用
void Start()
{
//加载主包 主包的名字和AB包生成路径一样
AssetBundle mainAssetBundle = AssetBundle.LoadFromFile(Application.streamingAssetsPath + "/" + "StandaloneWindows");
//加载AB包依赖关系清单文件
//AssetBundleManifest是Unity中用于管理AB包依赖关系的类。
AssetBundleManifest assetBundleManifest = mainAssetBundle.LoadAsset
//GetAllDependencies方法 传入AB包名得到AB包依赖的所有AB包
string[] modelDependencieAssetBundleNameArray = assetBundleManifest.GetAllDependencies("model");
//遍历依赖的所有AB包
for (int i = 0;i< modelDependencieAssetBundleNameArray.Length;i++)
{
Debug.Log(modelDependencieAssetBundleNameArray[i]);//输出icon
AssetBundle.LoadFromFile(Application.streamingAssetsPath + "/" + modelDependencieAssetBundleNameArray[i]);//遍历加载所有依赖的AB包
}
//加载生成的cube
AssetBundle modelAssetBundle = AssetBundle.LoadFromFile(Application.streamingAssetsPath + "/" + "model");
GameObject cube = modelAssetBundle.LoadAsset("Cube", typeof(GameObject)) as GameObject;
Instantiate(cube);
}
}
效果,生成的cube因为加载了所需要的所有依赖包 不会丢失材质
五、封装AB包资源管理器
1、继承MonoBehaviour的泛型单例模式基类
参考:unity框架开发
using UnityEngine;
///
/// 继承MonoBehaviour的泛型单例基类
///
public class SingletonMono
{
//记录单例对象是否存在。用于防止在OnDestroy方法中访问单例对象报错
public static bool IsExisted { get; private set; } = false;
private static T instance;
public static T Instance
{
get
{
if (instance == null)
{
instance = FindFirstObjectByType
if (instance == null)
{
GameObject go = new GameObject(typeof(T).Name); // 创建游戏对象
instance = go.AddComponent
}
}
DontDestroyOnLoad(instance);
IsExisted = true;
return instance;
}
}
// 构造方法私有化,防止外部 new 对象
protected SingletonMono() { }
private void OnDestroy() {
IsExisted = false;
}
}
2、封装AssetBundle管理器
这里其实用到的都是前面说过的知识,只是将他们统一进行封装而已,这里就不多介绍了
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
///
/// AssetBundle管理器
///
public class AssetBundleManager : SingletonMono
{
#region 变量
private AssetBundle mainAssetBundle = null; // 主 AssetBundle
private AssetBundleManifest assetBundleManifest = null; // AssetBundle 清单
private Dictionary
///
/// 获取 AssetBundle 文件夹的路径
///
private string assetBundleFolderPath
{
get
{
return Application.streamingAssetsPath + "/";
}
}
///
/// 获取主 AssetBundle 的名称
///
private string mainAssetBundleName
{
get
{
#if UNITY_IOS
return "IOS";
#elif UNITY_ANDROID
return "Android";
#else
return "PC";
#endif
}
}
#endregion
#region 加载包
///
/// 加载主 AssetBundle 和 AssetBundle 清单
///
// 加载主资源包和资源包清单
// 加载主资源包和资源包清单
private void LoadMainAssetBundleAndAssetBundleManifest()
// 如果主资源包为空
{
if (mainAssetBundle == null)
// 从文件中加载主资源包
{
// 从主资源包中加载资源包清单
mainAssetBundle = AssetBundle.LoadFromFile(assetBundleFolderPath + mainAssetBundleName);
assetBundleManifest = mainAssetBundle.LoadAsset
}
}
///
/// 加载 AssetBundle 的依赖项
///
private void LoadAssetBundleDependencies(string assetBundleName)
{
LoadMainAssetBundleAndAssetBundleManifest();
string[] strs = assetBundleManifest.GetAllDependencies(assetBundleName);
for (int i = 0; i < strs.Length; i++)
{
if (!assetBundleDictionary.ContainsKey(strs[i]))
{
AssetBundle ab = AssetBundle.LoadFromFile(assetBundleFolderPath + strs[i]);
assetBundleDictionary.Add(strs[i], ab);
}
}
}
///
/// 加载目标 AssetBundle
///
private void LoadAssetBundleTarget(string assetBundleName)
{
if (!assetBundleDictionary.ContainsKey(assetBundleName))
{
AssetBundle assetBundle = AssetBundle.LoadFromFile(assetBundleFolderPath + assetBundleName);
assetBundleDictionary.Add(assetBundleName, assetBundle);
}
}
///
/// 加载目标 AssetBundle 和其依赖项
///
private void LoadAssetBundleTargetAndDependencies(string assetBundleName)
{
LoadAssetBundleDependencies(assetBundleName);
LoadAssetBundleTarget(assetBundleName);
}
#endregion
#region 同步加载
///
/// 如果资源是 GameObject,则实例化;否则返回原始资源
///
private T InstantiateIfGameObject
{
if (resource is GameObject)
{
return Instantiate(resource);
}
else
{
return resource;
}
}
///
/// 同步加载 AssetBundle 中的资源
///
public T LoadAssetBundleResource
{
LoadAssetBundleTargetAndDependencies(assetBundleName);
T resource = assetBundleDictionary[assetBundleName].LoadAsset
return InstantiateIfGameObject
}
///
/// 同步加载 AssetBundle 中的资源,指定资源类型
///
public Object LoadAssetBundleResource(string assetBundleName, string resourceName, System.Type type)
{
LoadAssetBundleTargetAndDependencies(assetBundleName);
Object resource = assetBundleDictionary[assetBundleName].LoadAsset(resourceName, type);
return InstantiateIfGameObject(resource);
}
///
/// 同步加载 AssetBundle 中的资源
///
public Object LoadAssetBundleResource(string assetBundleName, string resourceName)
{
LoadAssetBundleTargetAndDependencies(assetBundleName);
Object resource = assetBundleDictionary[assetBundleName].LoadAsset(resourceName);
return InstantiateIfGameObject(resource);
}
#endregion
#region 异步加载
///
/// 如果资源是 GameObject,则实例化后执行回调;否则直接执行回调
///
private void InstantiateIfGameObjectAndCallBack
{
if (resource is GameObject)
callBack(Instantiate(resource) as T);
else
callBack(resource as T);
}
///
/// 异步加载 AssetBundle 中的资源
///
public void LoadAssetBundleResourceAsync
{
StartCoroutine(LoadAssetBundleResourceAsyncCoroutine
}
///
/// 异步加载 AssetBundle 中的资源,指定资源类型
///
private IEnumerator LoadAssetBundleResourceAsyncCoroutine
{
LoadAssetBundleTargetAndDependencies(assetBundleName);
AssetBundleRequest assetBundleRequest = assetBundleDictionary[assetBundleName].LoadAssetAsync
yield return assetBundleRequest;
InstantiateIfGameObjectAndCallBack
}
///
/// 异步加载 AssetBundle 中的资源,指定资源类型
///
public void LoadAssetBundleResourceAsync(string assetBundleName, string resourceName, System.Type type, UnityAction
{
StartCoroutine(LoadAssetBundleResourceAsyncCoroutine(assetBundleName, resourceName, type, callBack));
}
///
/// 异步加载 AssetBundle 中的资源
///
private IEnumerator LoadAssetBundleResourceAsyncCoroutine(string assetBundleName, string resourceName, System.Type type, UnityAction
{
LoadAssetBundleTargetAndDependencies(assetBundleName);
AssetBundleRequest assetBundleRequest = assetBundleDictionary[assetBundleName].LoadAssetAsync(resourceName, type);
yield return assetBundleRequest;
InstantiateIfGameObjectAndCallBack(assetBundleRequest.asset, callBack);
}
///
/// 异步加载 AssetBundle 中的资源
///
public void LoadAssetBundleResourceAsync(string assetBundleName, string resourceName, UnityAction
{
StartCoroutine(LoadAssetBundleResourceAsyncCoroutine(assetBundleName, resourceName, callBack));
}
///
/// 异步加载 AssetBundle 中的资源
///
private IEnumerator LoadAssetBundleResourceAsyncCoroutine(string assetBundleName, string resourceName, UnityAction
{
LoadAssetBundleTargetAndDependencies(assetBundleName);
AssetBundleRequest assetBundleRequest = assetBundleDictionary[assetBundleName].LoadAssetAsync(resourceName);
yield return assetBundleRequest;
InstantiateIfGameObjectAndCallBack(assetBundleRequest.asset, callBack);
}
#endregion
#region 卸载包
///
/// 卸载指定名称的 AssetBundle
///
public void UnLoadAssetBundle(string name)
{
if (assetBundleDictionary.ContainsKey(name))
{
assetBundleDictionary[name].Unload(false);
assetBundleDictionary.Remove(name);
}
}
///
/// 清理所有 AssetBundle
///
public void ClearAssetBundle()
{
AssetBundle.UnloadAllAssetBundles(false);
assetBundleDictionary.Clear();
mainAssetBundle = null;
assetBundleManifest = null;
}
#endregion
}
注意:记得AB打包文件夹名称要根据不同平台修改成对应的IOS、Android、PC
3、调用测试
using UnityEngine;
public class LoadAB : MonoBehaviour
{
void Start()
{
// 加载预制体cube
AssetBundleManager.Instance.LoadAssetBundleResource
// 加载预制体sphere
AssetBundleManager.Instance.LoadAssetBundleResourceAsync
{
//修改位置
sphere.transform.position = new Vector3(2, 2, 2);
});
//卸载指定名称的 AssetBundle
// AssetBundleManager.Instance.UnLoadAssetBundle("model");
//清理所有 AssetBundle
// AssetBundleManager.Instance.ClearAssetBundle();
}
}
效果
六、总结
Unity从2018.2版本开始推荐使用Addressable Asset System(可寻址资源系统)作为AssetBundle的替代方案。Addressables基于AssetBundle架构,但提供了更高级的功能,如自动化依赖管理、内存优化、远程资源加载、增量更新等。它简化了AssetBundle的打包、加载和更新流程,降低了开发者的使用门槛。
Addressables是Unity推荐的现代资源管理方案,未来会逐步取代AssetBundle。但AssetBundle不会完全消失:由于历史项目、特殊优化需求、底层技术依赖等原因,AssetBundle仍然是开发者需要掌握的重要知识。
新项目:优先使用Addressables,减少开发复杂度,提高热更新和资源管理效率。老项目:如果已有成熟的AssetBundle方案,可逐步迁移;若项目较稳定,也可继续沿用。
不会Addressables的同学也不用担心,Addressables相关知识我后面会单独出文章进行讲解。
专栏推荐
地址【unity游戏开发入门到精通——C#篇】【unity游戏开发入门到精通——unity通用篇】【unity游戏开发入门到精通——unity3D篇】【unity游戏开发入门到精通——unity2D篇】【unity实战】【制作100个Unity游戏】【推荐100个unity插件】【实现100个unity特效】【unity框架/工具集开发】【unity游戏开发——模型篇】【unity游戏开发——InputSystem】【unity游戏开发——Animator动画】【unity游戏开发——UGUI】【unity游戏开发——联网篇】【unity游戏开发——优化篇】【unity游戏开发——shader篇】【unity游戏开发——编辑器扩展】【unity游戏开发——热更新】
完结
好了,我是向宇,博客地址:https://xiangyu.blog.csdn.net,如果学习过程中遇到任何问题,也欢迎你评论私信找我。
赠人玫瑰,手有余香!如果文章内容对你有所帮助,请不要吝啬你的点赞评论和关注,你的每一次支持都是我不断创作的最大动力。当然如果你发现了文章中存在错误或者有更好的解决方法,也欢迎评论私信告诉我哦!