Unity 3D 简易对象池

  • 依赖于UniTask(访问Github)
  • 依赖于Addressable资源管理(通过UPM安装)
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);
            }
        }

    }
}
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);
        }
    }
}

猜你喜欢

转载自blog.csdn.net/qq_46273241/article/details/133241236