- 依赖于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()
{
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>();
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();
}
public Pool GetPool(string key)
{
if (!pools.ContainsKey(key)) return null;
return pools[key];
}
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);
}
public UniTask<GameObject> GetAsync(string key)
{
var pool = GetPool(key) ?? throw new InvalidOperationException("Please get after create pool");
return pool.Get();
}
public GameObject GetSync(string key)
{
var pool = GetPool(key) ?? throw new InvalidOperationException("Please get after create pool");
return pool.GetSync();
}
public void Recycle(string key, GameObject obj)
{
var pool = GetPool(key) ?? throw new InvalidOperationException("Please set after create pool");
pool.Set(obj);
}
public async UniTask<T> GetComponentAsync<T>(string key) where T : Component
{
var pool = GetPool(key);
return (await pool.Get()).GetComponent<T>();
}
public T GetComponentSync<T>(string key) where T : Component
{
var pool = GetPool(key);
return pool.GetSync().GetComponent<T>();
}
public void RecycleComponent<T>(string key, T com) where T : Component
{
var pool = GetPool(key);
pool.Set(com.gameObject);
}
}
}