264 lines
8.3 KiB
C#
264 lines
8.3 KiB
C#
/********************************************************************************
|
||
* 文件名: 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();
|
||
}
|
||
}
|
||
}
|