1. 如需资源热更可以勾选此选项
2. 将需要加载的资源拖到Group下并修改Group的加载方式
2.1 将该Group的加载方式改为远程
3. 配置存储桶并修改Addressable的远程加载路径
以腾讯云为例各家对象存储页面可能有点差异,请自行查阅相关文档。
3.1 将访问权限改为公有读私有写
3.2 复制访问域名并修改Addressable的加载路径
[BuildTarget] 对应当前的平台
4. 完成上述操作后即可打包部署到对象存储桶
4.1 打包bundle
打包路径在AddressableAssetSettings可以查看,默认路径在项目的根目录
4.2 上传至对象存储桶(将打包好的文件夹整体上传)
5. 加载资源
5.1 制作下载进度条并将 DownloadProgressPanel 脚本挂到其父物体
using TMPro;
using UnityEngine;
using UnityEngine.UI;
public class DownloadProgressPanel : MonoBehaviour
{
public Image progressBarImage;
public TMP_Text progressTMP;
public TMP_Text downloadSizeTMP;
private void OnEnable()
{
progressBarImage.fillAmount = 0f;
progressTMP.text = "0%";
downloadSizeTMP.text = "资源下载中(0MB/0MB)";
}
}
5.2 创建空物体并将 ResourceManager 挂到该物体上
Mono单例
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MonoSingleton<T> : MonoBehaviour where T : MonoBehaviour
{
private static T _instance;
public static T Instancea
{
get
{
if (_instance == null)
{
_instance = FindObjectOfType<T>();
if (_instance == null)
{
GameObject singletonObject = new GameObject();
_instance = singletonObject.AddComponent<T>();
singletonObject.name = typeof(T).ToString() + " (Singleton)";
DontDestroyOnLoad(singletonObject);
}
}
return _instance;
}
}
protected virtual void Awake()
{
if (_instance == null)
{
_instance = this as T;
DontDestroyOnLoad(gameObject);
}
else
{
Destroy(gameObject);
}
}
}
using System;
using System.Collections;
using UnityEngine.AddressableAssets;
using UnityEngine.AddressableAssets.ResourceLocators;
using UnityEngine.ResourceManagement.AsyncOperations;
using UnityEngine.SceneManagement;
using Debug = UnityEngine.Debug;
public class ResourceManager : MonoSingleton<ResourceManager>
{
private void OnEnable()
{
Addressables.InitializeAsync().Completed += AddressableInitialize;
}
private void AddressableInitialize(AsyncOperationHandle<IResourceLocator> assets)
{
print("Addressable Initialization Complete");
}
/// <summary>
/// 加载资源
/// </summary>
/// <param name="address">资源名称</param>
/// <param name="onStartCallback">开始加载回调</param>
/// <param name="onProgressTracker">进度回调</param>
/// <param name="onComplete">完成加载回调</param>
/// <typeparam name="T"></typeparam>
public void LoadAsset<T>(string address,Action onStartCallback=null,Action<ProgressTracker> onProgressTracker=null,Action<T> onComplete=null) where T : UnityEngine.Object
{
StartCoroutine(CoroutineLoadAsset(address,onStartCallback,onProgressTracker,onComplete));
}
IEnumerator CoroutineLoadAsset<T>(string assetLabel,Action onStartCallback=null,Action<ProgressTracker> onProgressTracker=null, Action<T> onCompleted=null) where T : UnityEngine.Object
{
// 初始化 Addressable
yield return Addressables.InitializeAsync();
onStartCallback?.Invoke();
var totalSize = 0f;
// 获取场景的下载大小
yield return GetDownLoadAssetSize(assetLabel, (size) => { totalSize = size; });
// 创建进度追踪器
var progress = new ProgressTracker(totalSize);
// 下载资源
var asset= Addressables.LoadAssetAsync<T>(assetLabel);
if (asset.Status == AsyncOperationStatus.Failed)
{
Debug.LogError("Asset Load Error: " + asset.OperationException);
yield break;
}
while (!asset.IsDone)
{
// 更新进度追踪器的进度
progress.UpdateProgress(asset.GetDownloadStatus().Percent, asset.GetDownloadStatus().DownloadedBytes);
onProgressTracker?.Invoke(progress);
yield return null;
}
onCompleted?.Invoke(asset.Result);
}
/// <summary>
/// 加载场景
/// </summary>
/// <param name="sceneLabel">场景名称</param>
/// <param name="onStartCallback">开始加载回调</param>
/// <param name="onProgressTracker">进度回调</param>
/// <param name="onCompleted">完成加载回调</param>
public void LoadScene(string sceneLabel,Action onStartCallback=null,Action<ProgressTracker> onProgressTracker=null,Action onCompleted=null)
{
StartCoroutine(CoroutineLoadScene(sceneLabel,onStartCallback,onProgressTracker,onCompleted));
}
IEnumerator CoroutineLoadScene(string sceneLabel,Action onStartCallback=null, Action<ProgressTracker> onProgressTracker=null,Action onCompleted = null)
{
// 初始化 Addressable
yield return Addressables.InitializeAsync();
onStartCallback?.Invoke();
var totalSize = 0f;
// 获取场景的下载大小
yield return GetDownLoadAssetSize(sceneLabel, (size) => { totalSize = size; });
// 创建进度追踪器
var progress = new ProgressTracker(totalSize);
// 下载场景并设定加载模式为Additive
var scene=Addressables.LoadSceneAsync(sceneLabel, LoadSceneMode.Additive);
if (scene.Status == AsyncOperationStatus.Failed)
{
Debug.LogError("Scene Load Error: " + scene.OperationException);
yield break;
}
while (!scene.IsDone)
{
// 更新进度追踪器的进度
progress.UpdateProgress(scene.GetDownloadStatus().Percent, scene.GetDownloadStatus().DownloadedBytes);
onProgressTracker?.Invoke(progress);
yield return null;
}
onCompleted?.Invoke();
}
/// <summary>
/// 获取资源大小
/// </summary>
/// <param name="assetLabel"></param>
/// <param name="callback"></param>
/// <returns></returns>
private IEnumerator GetDownLoadAssetSize(string assetLabel,Action<float> callback)
{
var downloadSizeHandle = Addressables.GetDownloadSizeAsync(assetLabel);
yield return downloadSizeHandle;
if (downloadSizeHandle.Status != AsyncOperationStatus.Succeeded)
{
Debug.LogError("Failed to get download size: " + downloadSizeHandle.OperationException);
yield break;
}
// 将下载大小转换为以MB为单位的浮点数
long downloadSize = downloadSizeHandle.Result;
float totalSize = (float)downloadSize / (1024 * 1024);
Debug.Log($"下载的资源大小:{downloadSize}");
callback?.Invoke(totalSize);
}
private void OnDisable()
{
Addressables.InitializeAsync().Completed -= AddressableInitialize;
}
}
public class ProgressTracker
{
private readonly float m_AssetTotalSize;
private float m_CurrentProgress;
private float m_CurrentDownloadSize;
public ProgressTracker(float assetTotalSize)
{
this.m_AssetTotalSize = assetTotalSize;
this.m_CurrentProgress = 0f;
}
/// <summary>
/// 更新下载进度
/// </summary>
/// <param name="percent">进度</param>
/// <param name="downloadedBytes">下载字节数</param>
public void UpdateProgress(float percent, long downloadedBytes)
{
m_CurrentDownloadSize = (float)downloadedBytes / (1024 * 1024);
m_CurrentProgress = percent;
}
/// <summary>
/// 获取下载进度
/// </summary>
/// <returns></returns>
public float GetProgress()
{
return m_CurrentProgress;
}
/// <summary>
/// 获取当前下载大小
/// </summary>
/// <returns></returns>
public float GetCurrentDownloadSize()
{
return m_CurrentDownloadSize;
}
/// <summary>
/// 获取资源总大小
/// </summary>
/// <returns></returns>
public float GetAssetTotalSize()
{
return m_AssetTotalSize;
}
/// <summary>
/// 标记完成
/// </summary>
public void Complete()
{
m_CurrentProgress = m_AssetTotalSize;
}
}
5.3 加载资源,创建空物体并挂上该脚本
using UnityEngine;
public class TestLoadObject : MonoBehaviour
{
[SerializeField]private DownloadProgressPanel progressPanel;
void Start()
{
ResourceManager.Instance.LoadAsset<GameObject>("Set Costume_02 SD Misaki", () =>
{
print($"---> Start Loader...");
},(tracker)=>
{
GetCurrentProgress(tracker.GetProgress(), tracker.GetCurrentDownloadSize(), tracker.GetAssetTotalSize());
print($"---> Update Progress...");
}, (obj) =>
{
progressPanel.gameObject.SetActive(false);
Instantiate(obj);
print($"---> Main Scene Load Complete!");
});
}
private void GetCurrentProgress(float percentage,float downloadSize,float totalSize)
{
progressPanel.progressBarImage.fillAmount = percentage;
progressPanel.progressTMP.text = $"{(percentage * 100f):f0}%";
progressPanel.downloadSizeTMP.text = $"资源下载中({downloadSize:f1}MB/{totalSize:f1}MB)";
}
}
5.4 加载场景,创建空物体并挂上该脚本
using UnityEngine;
public class TestLoadScene : MonoBehaviour
{
[SerializeField]private DownloadProgressPanel progressPanel;
void Start()
{
ResourceManager.Instance.LoadScene("MainScene", () =>
{
progressPanel.gameObject.SetActive(true);
print($"---> Start Loader...");
},(tracker)=>
{
GetCurrentProgress(tracker.GetProgress(), tracker.GetCurrentDownloadSize(), tracker.GetAssetTotalSize());
print($"---> Update Progress...");
}, () =>
{
progressPanel.gameObject.SetActive(false);
print($"---> Main Scene Load Complete!");
});
}
private void GetCurrentProgress(float percentage,float downloadSize,float totalSize)
{
progressPanel.progressBarImage.fillAmount = percentage;
progressPanel.progressTMP.text = $"{(percentage * 100f):f0}%";
progressPanel.downloadSizeTMP.text = $"资源下载中({downloadSize:f1}MB/{totalSize:f1}MB)";
}
}
6. 打包运行
加载单个资源
加载场景
下载内容大小提示
7.更新
2023.08.16
- 新增进度追踪器脚本
- 新增下载内容大小提示
- 新增 Addressable 初始化操作
- 优化 ResourceManager 提供更多的回调参数
2023.08.30
- 优化 ResourceManager 更加精简