2024-08-23 15:49:34 +08:00

264 lines
8.3 KiB
C#
Raw 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.

/********************************************************************************
* 文件名: GameObjectPool.cs
* 全路径: \Script\GameManager\GameObjectPool.cs
* 创建人: 李嘉
* 创建时间2014-04-15
*
* 功能说明:自增长池类
* 当池子中对象满的时候,会创建并且插入,如果发现有删除的对象则复用。
* 删除对象的时候池子中的数量并不会减少,而是将对象变为可复用。
* 对外只提供Create和Remove接口
* 池子的作用是避免过多的GC行为发生在内存略微增长的前提下达到帧率的平滑稳定。
* 注意如果对象的销毁函数Destroy中包含对class赋空的情况则无法避免GC行为此时不一定要使用该池
* 另外千万不要在其他逻辑中将list中的GameObject状态置true和false否则在取的时候会失效此时宁可不用Pool
* 修改记录:
* LiJia 2014-09-17 将尺子改为自增长但是最大可能只有POOL_MAX_CAPACITY定义的数量
*********************************************************************************/
using System.Collections.Generic;
using Games.GlobeDefine;
using UnityEngine;
using Module.Log;
public class GameObjectPool
{
public delegate void CreatePoolObjDelegate(GameObject newObj, object param1, object param2);
private class LoadBundleParam
{
public LoadBundleParam(CreatePoolObjDelegate delFun, object param1, object param2, UIPathData uiData, string objName)
{
m_delFun = delFun;
m_userParam1 = param1;
m_userParam2 = param2;
m_uiData = uiData;
m_objName = objName;
}
public CreatePoolObjDelegate m_delFun;
public object m_userParam1;
public object m_userParam2;
public UIPathData m_uiData;
public string m_objName;
}
private GameObjectPool()
{
}
public GameObjectPool(string szPoolName, int nMaxSize = GlobeVar.INVALID_ID)
{
m_szPoolName = szPoolName;
m_ActivePool = new Dictionary<string, List<GameObject>>();
m_InActivePool = new Dictionary<string, List<GameObject>>();
m_nMaxSize = nMaxSize;
}
private string m_szPoolName; //池子名称
public string PoolName
{
get { return m_szPoolName; }
}
private Dictionary<string, List<GameObject>> m_ActivePool; //活动对象队列
private Dictionary<string, List<GameObject>> m_InActivePool; //非活动对象队列
private int m_nMaxGameObjectType = 64; //池子中索引的数量
private int m_nMaxSize = 128; //池子中每种类型的GameObject可容纳的子队列大小
// 从Bundle加载一个可复用的ITEM
public void CreateUIFromBundle(UIPathData uiData, string objName, CreatePoolObjDelegate delFun, object param1, object param2)
{
GameObject obj = ReUseElement(objName);
if (null == obj)
{
if (m_nMaxGameObjectType > 0 && m_ActivePool.Count == m_nMaxGameObjectType)
{
if(null != delFun) delFun(null, param1, param2);
return;
}
}
else
{
if(null != delFun) delFun(obj, param1, param2);
}
}
private void OnLoadBundleItem(GameObject resObj, object param)
{
LoadBundleParam curParam = param as LoadBundleParam;
if (null == curParam)
return;
GameObject newElement = GameObject.Instantiate(resObj) as GameObject;
if (null != newElement)
{
newElement.name = curParam.m_objName;
if (false == InsertElement(m_ActivePool, newElement))
{
//这里必须将newElement强制释放雕否则会导致Pool管理失效newElement无限增加
//后面所有用到newElement的地方原理相同
GameObject.Destroy(newElement);
}
if (null != curParam.m_delFun)
curParam.m_delFun(newElement, curParam.m_userParam1, curParam.m_userParam2);
}
}
public void Remove(GameObject element)
{
if (null == element)
return;
if (RemoveElement(m_ActivePool, element))
{
//插入都未使用队列
if (InsertElement(m_InActivePool, element))
{
element.transform.position = GlobeVar.INFINITY_FAR;
}
else
{
//插入失败需要把element释放掉否则会变成不受管理的GameObject
GameObject.Destroy(element);
}
}
}
//复用一个已经无效的对象
private GameObject ReUseElement(string strGameObjectName)
{
GameObject reuseElem = null;
if (m_InActivePool.ContainsKey(strGameObjectName))
{
List<GameObject> list = m_InActivePool[strGameObjectName];
if (null == list || list.Count <= 0)
return null;
reuseElem = list[0];
if (reuseElem == null)
{
list.RemoveAt(0);
return null;
}
list.Remove(reuseElem);
if (InsertElement(m_ActivePool, reuseElem))
{
return reuseElem;
}
else
{
//插入失败,释放掉
GameObject.Destroy(reuseElem);
}
}
return null;
}
//内部接口
//向池子中插入一个新的GameObject
private bool InsertElement(Dictionary<string, List<GameObject>> pool, GameObject newElement)
{
if (null == newElement || null == pool)
{
return false;
}
//先判断池子中是否有这个Key,如果没有则先添加
List<GameObject> list = null;
if (false == pool.ContainsKey(newElement.name))
{
list = new List<GameObject>();
pool.Add(newElement.name, list);
}
else
{
list = pool[newElement.name];
}
if (null != list)
{
//池子已达到最大
if (m_nMaxSize > 0 && list.Count >= m_nMaxSize)
{
if (list.Count < GlobeVar.POOL_MAX_CAPACITY)
{
m_nMaxSize++;
}
else
{
LogModule.ErrorLog("Pool has reached capacity size, Element name:" + newElement.name);
return false;
}
}
list.Add(newElement);
return true;
}
return false;
}
//从池子中移除一个GameObject
private bool RemoveElement(Dictionary<string, List<GameObject>> pool, GameObject element)
{
if (null == element || null == pool)
{
return false;
}
if (pool.ContainsKey(element.name))
{
List<GameObject> list = pool[element.name];
if (null != list && list.Contains(element))
{
list.Remove(element);
return true;
}
}
return false;
}
//清理所有的GameObjectPool
public void ClearAllPool()
{
if (null != m_ActivePool)
{
foreach(KeyValuePair<string, List<GameObject>> activeList in m_ActivePool)
{
if (null != activeList.Value)
{
for(int i=0; i<activeList.Value.Count; ++i)
{
activeList.Value[i] = null;
}
activeList.Value.Clear();
}
}
m_ActivePool.Clear();
}
if (null != m_InActivePool)
{
foreach (KeyValuePair<string, List<GameObject>> inactiveList in m_InActivePool)
{
if (null != inactiveList.Value)
{
for (int i = 0; i < inactiveList.Value.Count; ++i)
{
inactiveList.Value[i] = null;
}
inactiveList.Value.Clear();
}
}
m_InActivePool.Clear();
}
}
}