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

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

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

2023.08.30

  1. 优化 ResourceManager 更加精简

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 12
    评论
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

今天喝水了嘛.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值