Unity 基于Addressable系统封装的通用方法

本文介绍了如何使用IAsyncOperationExtensions进行异步操作的简化处理,以及AddressablesManager类中关于场景加载、资源管理和对象实例化的详细示例。通过这些方法,开发者可以更高效地管理和加载游戏资源。
摘要由CSDN通过智能技术生成

IAsyncOperationExtensions:

using System;
using System.Runtime.CompilerServices;
using UnityEngine.ResourceManagement.AsyncOperations;

public static class IAsyncOperationExtensions
{
    public static AsyncOperationAwaiter GetAwaiter(this AsyncOperationHandle operation)
    {
        return new AsyncOperationAwaiter(operation);
    }

    public static AsyncOperationAwaiter<T> GetAwaiter<T>(this AsyncOperationHandle<T> operation) where T : class
    {
        return new AsyncOperationAwaiter<T>(operation);
    }

    public readonly struct AsyncOperationAwaiter : INotifyCompletion
    {
        readonly AsyncOperationHandle _operation;

        public AsyncOperationAwaiter(AsyncOperationHandle operation)
        {
            _operation = operation;
        }

        public bool IsCompleted => _operation.Status != AsyncOperationStatus.None;

        public void OnCompleted(Action continuation) => _operation.Completed += (op) => continuation?.Invoke();

        public object GetResult() => _operation.Result;
    }

    public readonly struct AsyncOperationAwaiter<T> : INotifyCompletion where T : class
    {
        readonly AsyncOperationHandle<T> _operation;

        public AsyncOperationAwaiter(AsyncOperationHandle<T> operation)
        {
            _operation = operation;
        }

        public bool IsCompleted => _operation.Status != AsyncOperationStatus.None;

        public void OnCompleted(Action continuation) => _operation.Completed += (op) => continuation?.Invoke();

        public T GetResult() => _operation.Result;
    }
}

AddressablesManager:

using System.Threading.Tasks;
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.ResourceProviders;
using UnityEngine.SceneManagement;
using UnityEngine.ResourceManagement.AsyncOperations;

namespace AddressablesManagement
{
    public class AddressablesManager : MonoBehaviour
    {
        private static AddressablesManager _instance;

        private bool _currentlyLoading;
        private Scene _currentlyLoadingScene;

        #region properties

        /// <summary>
        /// 当前是否正在加载对象
        /// </summary>
        public bool CurrentlyLoading
        {
            get { return _currentlyLoading; }
            private set { _currentlyLoading = value; }
        }

        /// <summary>
        /// 该类的实例对象
        /// </summary>
        public static AddressablesManager Instance
        {
            get
            {
                if (_instance == null)
                {
                    Create();
                }

                return _instance;
            }
        }

        #endregion

        private void Awake()
        {
            if (_instance == null)
            {
                _instance = this;
                DontDestroyOnLoad(this);
            }
            else
            {
                Destroy(this);
            }
        }

        #region public methods

        /// <summary>
        /// 加载场景
        /// </summary>
        /// <param name="sceneName">要加载场景的名称</param>
        /// <param name="loadMode">场景加载的方式</param>
        public Task<Scene> LoadScene(string sceneName, LoadSceneMode loadMode)
        {
            _currentlyLoadingScene = default;
            _currentlyLoadingScene.name = "";

            var handle = Addressables.LoadSceneAsync(sceneName, loadMode);
            handle.Completed += AddressablesManager_OnSceneLoadCompleted;


            if (string.IsNullOrEmpty(_currentlyLoadingScene.name))
            {
                Task.Delay(1);
            }

            return Task.Run(() => _currentlyLoadingScene);
        }

        private void AddressablesManager_OnSceneLoadCompleted(AsyncOperationHandle<SceneInstance> obj)
        {
            if (obj.Status == AsyncOperationStatus.Succeeded)
            {
                _currentlyLoadingScene = obj.Result.Scene;
            }
        }

        /// <summary>
        /// 按照给定模式(Single/Additive)加载场景到当前场景中
        /// </summary>
        /// <param name="sceneName">加载场景的名称</param>
        /// <param name="loadMode">场景加载模式</param>
        public async Task OnlyLoadScene(string sceneName, LoadSceneMode loadMode)
        {
            await Task.Run(() => Addressables.LoadSceneAsync(sceneName, loadMode));
        }

        /// <summary>
        /// 从内存中异步卸载给定场景。
        /// </summary>
        /// <param name="scene">要卸载的场景对象</param>
        public async Task UnloadScene(SceneInstance scene)
        {
            Addressables.UnloadSceneAsync(scene);
        }

        /// <summary>
        /// 实例化对象并且给定位置和旋转
        /// </summary>
        /// <param name="path">要实例化对象的名称</param>
        /// <param name="position">实例化对象的位置</param>
        /// <param name="rotation">实例化对象的旋转</param>
        /// <returns>返回要实例化的游戏对象集</returns>
        public async Task<GameObject> InstantiateGameObject(string path, Vector3 position, Quaternion rotation)
        {
            return await Addressables.InstantiateAsync(path, position, rotation);
        }

        /// <summary>
        /// 实例化游戏中的默认位置和旋转位置。
        /// </summary>
        /// <param name="path">游戏对象所在的项目路径。</param>
        /// <returns>返回要实例化的游戏对象集</returns>
        public async Task<GameObject> InstantiateGameObject(string path)
        {
            return await Addressables.InstantiateAsync(path, Vector3.zero, Quaternion.identity);
        }

        /// <summary>
        /// 将 T 类型的对象加载到内存中。
        /// </summary>
        /// <typeparam name="T">所要加载对象的类型</typeparam>
        /// <param name="path">要在可寻址系统中加载的对象的路径。</param>
        /// <returns>返回 T 类型的对象。</returns>
        public async Task<T> Load<T>(string path) where T : class
        {
            return await Addressables.LoadAssetAsync<T>(path);
        }

        /// <summary>
        /// 按给定路径预加载对象的所有依赖项
        /// </summary>
        /// <param name="path">要从中加载依赖项的对象的路径。</param>
        public async Task DownloadDependencies(string path)
        {
            await Addressables.DownloadDependenciesAsync(path);
        }

        /// <summary>
        /// 将给定标签的所有资源加载到内存中。
        /// </summary>
        /// <typeparam name="T">索要加载资源的类型</typeparam>
        /// <param name="label">在要加载的对象的可寻址对象中标记标签。</param>
        /// <param name="callback">加载后执行的回调</param>
        /// <returns>返回包含 T 类型元素的列表。</returns>
        public async Task<List<T>> LoadAssetsByLabel<T>(string label, Action<T> callback = null) where T : class
        {
            return await Addressables.LoadAssetsAsync<T>(label, callback) as List<T>;
        }


        /// <summary>
        /// 从内存中释放预制件并销毁其在当前活动场景中的实例。
        /// </summary>
        /// <param name="obj">要释放的预制件的游戏对象引用。</param>
        public void ReleaseInstance(ref GameObject obj)
        {
            if (obj != null)
                Addressables.ReleaseInstance(obj);
        }

        /// <summary>
        /// 从内存中释放给定对象。
        /// </summary>
        /// <typeparam name="T">要释放的对象的类型。</typeparam>
        /// <param name="obj">要释放的对象引用。</param>
        public void ReleaseAsset<T>(ref T obj) where T : class
        {
            if (obj != null)
                Addressables.Release(obj);
        }

        #endregion

        /// <summary>
        /// 创建以可寻址管理器为组件的游戏对象。
        /// </summary>
        private static void Create()
        {
            new GameObject("AddressablesManager").AddComponent<AddressablesManager>();
        }

        private void OnApplicationQuit()
        {
            StopAllCoroutines();
        }
    }
}

以下脚本为使用示例脚本:

using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.ResourceManagement.ResourceProviders;

namespace AddressablesManagement
{
    public class AddressablesExample : MonoBehaviour
    {
        public GameObject loneGameObject;
        public GameObject[] testObjects = new GameObject[50];
        public List<Material> materials;
        public List<Sprite> _sprites;
        public List<string> listTest;
        public Sprite sprite;
        private Vector3 startingPos;
        private Scene sceneToLoad;

        void Start()
        {
            // materials = new List<Material>(3);
            // startingPos = transform.position;
            LoadScene("SceneTest", LoadSceneMode.Single);
            // InstantiateSingleObject("TestSphere");
            // TestInstantiateObjects();
            // TestLoadByLabel();
            // LoadSprite("BG");
            // TestLoadByLabel_Sprite();
            // LoadFromList(listTest);
        }

        async void TestLoadByLabel()
        {
            materials = await AddressablesManager.Instance.LoadAssetsByLabel<Material>("materials");
        }

        async void TestLoadByLabel_Sprite()
        {
            _sprites = await AddressablesManager.Instance.LoadAssetsByLabel<Sprite>("sprites");
        }

        /// <summary>
        /// 生成多个物体
        /// </summary>
        async void TestInstantiateObjects()
        {
            Vector3 pos = startingPos;

            for (int i = 0; i < testObjects.Length; i++)
            {
                testObjects[i] = await AddressablesManager.Instance.InstantiateGameObject("TestObject");
                testObjects[i].transform.position = pos;
                pos += new Vector3(2f, 0, 0);
            }
        }

        /// <summary>
        /// 根据路径加载对象
        /// </summary>
        /// <param name="path"></param>
        async void InstantiateSingleObject(string path)
        {
            loneGameObject = await AddressablesManager.Instance.InstantiateGameObject(path);
        }

        /// <summary>
        /// 根据路径加载图片
        /// </summary>
        /// <param name="path">精灵路径</param>
        async void LoadSprite(string path)
        {
            sprite = await AddressablesManager.Instance.Load<Sprite>(path);
        }

        /// <summary>
        /// 加载场景
        /// </summary>
        /// <param name="sceneName"></param>
        /// <param name="loadSceneMode"></param>
        async void LoadScene(string sceneName, LoadSceneMode loadSceneMode)
        {
            sceneToLoad = await AddressablesManager.Instance.LoadScene(sceneName, loadSceneMode);
        }

        /// <summary>
        /// 卸载场景
        /// </summary>
        /// <param name="scene"></param>
        async void UnloadScene(SceneInstance scene)
        {
            await AddressablesManager.Instance.UnloadScene(scene);
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值