Unity 3D 简易对象池

  • 依赖于UniTask(访问Github)
  • 依赖于Addressable资源管理(通过UPM安装)
csharp 复制代码
using Cysharp.Threading.Tasks;
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;


namespace EasyAVG
{

    public class Pool
    {

        public Action<GameObject> OnGet { get; set; } = defaultGet;
        public Action<GameObject> OnSet { get; set; } = defaultSet;
        public Action<GameObject> OnDestroy { get; set; } = defaultDestroy;

        public Action<GameObject> OnCreate { get; set; } = null;

        public int MaxCount { get; set; } = int.MaxValue;

        public int MinCount { get; set; } = 0;

        public string Location { get; set; } = null;





        private Queue<GameObject> queue = new Queue<GameObject>();


        static readonly Action<GameObject> defaultGet = (x) =>
            {
                x.SetActive(true);
            }
        , defaultSet = (x) =>
        {
            x.SetActive(false);
        }
        , defaultDestroy = (x) =>
        {
            GameObject.Destroy(x);
        };



        internal bool _destroyed = false;
        private IEnumerator PoolThread()
        {

            //cacheHandle = Addressables.LoadAssetAsync<GameObject>(Location);
            //yield return cacheHandle;
            while (true)
            {
                if (_destroyed)
                {
                    yield break;
                }
                if (MinCount > MaxCount) throw new InvalidOperationException($"Please keep MaxCount>MinCount . CurrentMin{MinCount}>CurreentMax{MaxCount}");
                if (queue.Count < MinCount)
                {

                    var handle = Addressables.InstantiateAsync(Location);
                    yield return handle;
                    OnCreate?.Invoke(handle.Result);
                    queue.Enqueue(handle.Result);
                }
                if (queue.Count > MaxCount)
                {
                    OnDestroy?.Invoke(queue.Dequeue());
                }
                yield return null;

            }

        }
        internal void InitPool()
        {
            PoolManager.Instance.StartCoroutine(PoolThread());
        }


        public async UniTask<GameObject> Get()
        {
            if (queue.Count == 0)
            {
                var handle = Addressables.InstantiateAsync(Location);
                await handle;
                OnCreate?.Invoke(handle.Result);
                OnGet?.Invoke(handle.Result);
                return handle.Result;
            }
            await UniTask.CompletedTask;
            var item = queue.Dequeue();
            OnGet?.Invoke(item);
            return item;
        }
        public GameObject GetSync()
        {
            if (queue.Count == 0)
            {
                var handle = Addressables.InstantiateAsync(Location);
                OnCreate?.Invoke(handle.Result);
                OnGet?.Invoke(handle.Result);
                return handle.Result;
            }
            var item = queue.Dequeue();
            OnGet?.Invoke(item);
            return item;
        }

        public void Set(GameObject item)
        {
            if (queue.Count >= MaxCount)
            {
                OnSet?.Invoke(item);
                OnDestroy?.Invoke(item);
                return;
            }
            else
            {
                OnSet?.Invoke(item);
                queue.Enqueue(item);
            }
        }

    }
}
csharp 复制代码
using Cysharp.Threading.Tasks;
using EasyAVG;
using System;
using System.Collections.Generic;
using UnityEngine;

namespace EasyAVG
{

    public class PoolManager :MonoSingleton<PoolManager>
    {
    

        void OnDestroy()
        {
            foreach (var kvp in pools)
            {
                kvp.Value._destroyed = true;
            }
            pools.Clear();
        }

    



        private readonly Dictionary<string, Pool> pools = new Dictionary<string, Pool>();


        /// <summary>
        /// 创建对象池
        /// </summary>
        /// <param name="key"></param>
        /// <param name="location"></param>
        /// <param name="minCount"></param>
        /// <param name="maxCount"></param>
        public void CreatePool(string key, string location, int minCount = 0, int maxCount = int.MaxValue
         )
        {
            if (pools.ContainsKey(key)) return;
            Pool pool = new Pool();

            pool.Location = location;
            pool.MinCount = minCount;
            pool.MaxCount = maxCount;
            pools.Add(key, pool);

            pool.InitPool();
        }


        /// <summary>
        /// 获取对象池
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public Pool GetPool(string key)
        {
            if (!pools.ContainsKey(key)) return null;
            return pools[key];
        }


        /// <summary>
        /// 销毁对象池
        /// </summary>
        /// <param name="key"></param>
        /// <param name="exThrow"></param>
        /// <exception cref="NullReferenceException"></exception>
        public void DestroyPool(string key, bool exThrow = false)
        {
            if (!pools.ContainsKey(key))
            {
                if (exThrow)
                    throw new NullReferenceException("Destroying non-existent pool is not allowed");
                else return;
            }
            pools[key]._destroyed = true;
            pools.Remove(key);
        }


        /// <summary>
        /// 异步获取对象
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        /// <exception cref="InvalidOperationException"></exception>
        public UniTask<GameObject> GetAsync(string key)
        {
            var pool = GetPool(key) ?? throw new InvalidOperationException("Please get after create pool");
            return pool.Get();
        }

        /// <summary>
        /// 同步获取对象
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        /// <exception cref="InvalidOperationException"></exception>
        public GameObject GetSync(string key)
        {
            var pool = GetPool(key) ?? throw new InvalidOperationException("Please get after create pool");
            return pool.GetSync();
        }

        /// <summary>
        /// 放回对象
        /// </summary>
        /// <param name="key"></param>
        /// <param name="obj"></param>
        /// <exception cref="InvalidOperationException"></exception>
        public void Recycle(string key, GameObject obj)
        {
            var pool = GetPool(key) ?? throw new InvalidOperationException("Please set after create pool");
            pool.Set(obj);
        }

        /// <summary>
        /// 异步获取组件
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <returns></returns>
        public async UniTask<T> GetComponentAsync<T>(string key) where T : Component
        {
            var pool = GetPool(key);
            return (await pool.Get()).GetComponent<T>();
        }

        /// <summary>
        /// 同步获取组件
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <returns></returns>
        public T GetComponentSync<T>(string key) where T : Component
        {
            var pool = GetPool(key);
            return pool.GetSync().GetComponent<T>();
        }

        /// <summary>
        /// 同步回收组件
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <param name="com"></param>
        public void RecycleComponent<T>(string key, T com) where T : Component
        {
            var pool = GetPool(key);
            pool.Set(com.gameObject);
        }
    }
}
相关推荐
元气少女小圆丶7 小时前
SenseGlove Nova 2+Unity开发笔记2
笔记·unity·游戏引擎
Zldaisy3d8 小时前
全球唯一仿真驱动自适应扫描路径新版本发布,金属3D打印工艺开发进入算法时代
算法·3d
Oiiouui9 小时前
Godot(4.x): 游戏管理器: Godot 内注入数据处理与总接口实现
游戏·游戏引擎·godot
大江东去浪淘尽千古风流人物11 小时前
【HaMeR】全Transformer架构的单目3D手部网格重建:ViT-H骨干+跨注意力MANO解码器源码深度解析
深度学习·3d·transformer·vit·手部重建·mano
五月君_11 小时前
继 React、Vue 之后,Three.js 也有 Skills 了!AI 写 3D 终于不“晕”了
javascript·vue.js·人工智能·react.js·3d
神仙别闹11 小时前
基于Object3D 实现光线追踪
数码相机·3d
想不明白的过度思考者11 小时前
Unity学习笔记——虚拟摇杆实现笔记(事件触发器的使用、UGUI 坐标转换)
笔记·学习·unity
魔士于安11 小时前
unity volumefog带各种demo第一人称 wsad 穿墙控制
游戏·unity·游戏引擎·贴图·模型
魔士于安14 小时前
红色文化馆技术文档
前端·unity·游戏引擎·贴图·模型
zttsm14 小时前
UBUNTU22.04安装ORB_SLAM3
3d