Unity 使用Addressable加载远程资源

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 挂到该物体上

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

  1. 新增进度追踪器脚本
  2. 新增下载内容大小提示
  3. 新增 Addressable 初始化操作
  4. 优化 ResourceManager 提供更多的回调参数

2023.08.30

  1. 优化 ResourceManager 更加精简

猜你喜欢

转载自blog.csdn.net/Test_Two/article/details/131981367