Files
3d-bianpo/Assets/Scripts/Core/PoolManager.cs
2026-03-03 11:30:53 +08:00

302 lines
8.0 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
/// <summary>
/// 对象池管理类,日常使用一下两个方法即可
/// 取对象Spawn(name/Prefab)回收对象Unspawn(name/Prefab)
/// </summary>
public class PoolManager : MonoBehaviour
{
private static readonly object lockObj = new object();
private static PoolManager _instance;
public static PoolManager Instance
{
get
{
if (_instance == null)
{
lock (lockObj)
{
PoolManager[] objs = FindObjectsOfType<PoolManager>();
if (objs != null)
{
for (int i = 0; i < objs.Length; i++)
{
DestroyImmediate(objs[i].gameObject);
}
}
GameObject go = new GameObject("PoolManager");
DontDestroyOnLoad(go);
_instance = go.AddComponent<PoolManager>();
}
}
return _instance;
}
}
//预制ID-对象池 集合
private Dictionary<int, ObjectPool> poolDic = new Dictionary<int, ObjectPool>();
//对象ID-对象池ID 集合
private Dictionary<int, int> itemDic = new Dictionary<int, int>();
/// <summary>
/// 取对象,通过对象实例
/// </summary>
public GameObject Spawn(GameObject prefab)
{
if (!poolDic.ContainsKey(prefab.GetInstanceID()))
{
CreateNewPool(prefab);
}
GameObject item = poolDic[prefab.GetInstanceID()].Spawn();
if (!itemDic.ContainsKey(item.GetInstanceID()))
{
itemDic.Add(item.GetInstanceID(), prefab.GetInstanceID());
}
else
{
itemDic[item.GetInstanceID()] = prefab.GetInstanceID();
}
return item;
}
/// <summary>
/// 回收对象
/// </summary>
public void Unspawn(GameObject go)
{
if (itemDic.ContainsKey(go.GetInstanceID()))
{
int id = itemDic[go.GetInstanceID()];
if (poolDic.ContainsKey(id))
{
poolDic[id].Unspawn(go);
itemDic.Remove(go.GetInstanceID());
}
else
{
Debug.LogError("回收对象失败 : " + go.name);
}
}
}
/// <summary>
/// 回收某个对象池中所有对象
/// </summary>
public void ClearPool(GameObject prefab)
{
int id = prefab.GetInstanceID();
if (poolDic.ContainsKey(id))
{
poolDic[id].UnspawnAll();
}
else
{
Debug.LogError("清空对象池失败 " + prefab.name);
}
List<int> list = new List<int>();
foreach (int key in itemDic.Keys)
{
if (itemDic[key] == id)
{
list.Add(key);
}
}
for (int i = 0; i < list.Count; i++)
{
itemDic.Remove(list[i]);
}
}
/// <summary>
/// 回收所有对象池
/// </summary>
public void ClearAll()
{
foreach (ObjectPool pool in poolDic.Values)
{
pool.UnspawnAll();
}
itemDic.Clear();
}
/// <summary>
/// 创建一个新的对象池
/// </summary>
public void CreateNewPool(GameObject prefab)
{
if (poolDic.ContainsKey(prefab.GetInstanceID()))
{
Debug.LogError("无法创建新的对象池,当前对象池已存在 : " + prefab.name);
return;
}
ObjectPool pool = new ObjectPool(prefab);
poolDic.Add(prefab.GetInstanceID(), pool);
}
/// <summary>
/// 创建一个新的对象池,并初始化
/// </summary>
public void CreateNewPool(GameObject prefab, int initSize)
{
if (poolDic.ContainsKey(prefab.GetInstanceID()))
{
Debug.LogError("无法创建新的对象池,当前对象池已存在 : " + prefab.name);
return;
}
ObjectPool pool = new ObjectPool(prefab);
pool.InitPool(initSize);
poolDic.Add(prefab.GetInstanceID(), pool);
}
/// <summary>
/// 创建一个新的对象池,并初始化,同时设定对象池最大容量
/// </summary>
public void CreateNewPool(GameObject prefab, int initSize, int maxSize)
{
if (poolDic.ContainsKey(prefab.GetInstanceID()))
{
Debug.LogError("无法创建新的对象池,当前对象池已存在 : " + prefab.name);
return;
}
ObjectPool pool = new ObjectPool(prefab, maxSize);
pool.InitPool(initSize);
poolDic.Add(prefab.GetInstanceID(), pool);
}
}
/// <summary>
/// 对象池-子池
/// </summary>
public class ObjectPool
{
//对象池元素
public GameObject prefab;
//对象池最大容量此值小于等于0时对象池动态增加不设上限
private int maxSize;
//对象池名称
public string Name
{
get { return prefab.name; }
}
//对象池当前容量
private int CurrentSize
{
get { return activeObjectList.Count + inactiveObjectList.Count; }
}
private List<GameObject> activeObjectList = new List<GameObject>(); //已用对象列表
private List<GameObject> inactiveObjectList = new List<GameObject>(); //待用对象列表
public ObjectPool(GameObject obj)
{
this.prefab = obj;
maxSize = -1;
}
public ObjectPool(GameObject obj, int maxCount)
{
this.prefab = obj;
maxSize = maxCount;
}
/// <summary>
/// 初始化对象池
/// </summary>
public void InitPool(int initSize)
{
if (maxSize > 0 && initSize > maxSize)
{
Debug.LogError("对象池初始容量不能超过其最大容量!!");
for (int i = 0; i < maxSize; i++)
{
GameObject go = GameObject.Instantiate(prefab);
go.name = prefab.name;
go.SetActive(false);
inactiveObjectList.Add(go);
}
}
else
{
for (int i = 0; i < initSize; i++)
{
GameObject go = GameObject.Instantiate(prefab);
go.name = prefab.name;
go.SetActive(false);
inactiveObjectList.Add(go);
}
}
}
/// <summary>
/// 取对象
/// </summary>
public GameObject Spawn()
{
if (inactiveObjectList.Count == 0)
{
if (maxSize > 0 && CurrentSize >= maxSize)
{
Debug.LogError("警告:对象池 " + Name + " 当前容量已达到最大设定值 : " + maxSize);
GameObject go = activeObjectList[0];
return go;
}
else
{
GameObject go = GameObject.Instantiate(prefab);
go.SetActive(true);
activeObjectList.Add(go);
return go;
}
}
else
{
GameObject go = inactiveObjectList[0];
go.SetActive(true);
inactiveObjectList.RemoveAt(0);
activeObjectList.Add(go);
return go;
}
}
/// <summary>
/// 回收对象
/// </summary>
public void Unspawn(GameObject go)
{
if (activeObjectList.Contains(go))
{
go.SetActive(false);
activeObjectList.Remove(go);
inactiveObjectList.Add(go);
}
else
{
Debug.LogError("回收对象异常,当前对象不在对象列表中!!");
}
}
/// <summary>
/// 回收池中所有对象
/// </summary>
public void UnspawnAll()
{
//回收修改
int count = activeObjectList.Count;
for (int i = 0; i < count; i++)
{
if (activeObjectList.Count >= 1)
{
Unspawn(activeObjectList[0]);
}
}
}
}