对象池模块结构如下:
对象池管理者管理各类对象池,所有池子存入字典。通过key索引获取。对于需要频繁创建的东西配置相应的对象池,。如角色,炮弹等。各类对象池内存有对应的对象,并且开放相应的获取和回收接口。由对象池管理者统一管理。
对象 可以通过resources加载或者AB包方式。这里采用resource加载。对象信息报含有资源路径,资源名称,初始化的个数即池子里存放个数,对象object和需要挂载的脚本等等信息。
///
/// 资源对象,对象池中分配的
///
[Serializable]
public class SourceObject
{
public string sourceDirect; //资源路径
public string sourceName; //资源的名称
public GameObject prefab;//prefab引用
public int preAllocCount = 8;//初始化时预分配对象数量
public int autoIncreaseCount = 8;//池中可增加对象数量
public Type scriptType = null; //对象挂载的脚本名称,反射获取
}
using UnityEngine;
using System.Collections;
using System;
//预设信息,用来回收时调用此信息
public class PrefabInfo : MonoBehaviour
{
public string sourceName;
//[HideInInspector]
public float lifetime = 0; //-1表示不执行OnEnable
private ParticleSystem ps = null; //回收特效要根据特效的播放时间
private Coroutine waitCorou = null; //执行的协程
private event ObjectPoolMgr.RecycleBack recycleBack = null; //回收时的回调
public bool isRecycle = true; //是否已经回收的标志位
public virtual void Init(string sourceName)
{
this.sourceName = sourceName;
isRecycle = true;
ps = GetComponent();
}
public virtual void OnEnable()
{
if (lifetime == -1)
return;
if (lifetime > 0)
{
Recycle(lifetime);
}
else if (ps != null)
{
//ps.Stop(true);
//ps.Play(true);
if (!ps.isPlaying)
ps.Play(true);
if (!ps.main.loop)
{
waitCorou = StartCoroutine(recyclePS());
}
}
}
public virtual void OnDisable()
{
if (waitCorou != null)
StopCoroutine(waitCorou);
}
private IEnumerator recycleWaitTime(float lifetime)
{
yield return new WaitForSeconds(lifetime);
ObjectPoolMgr._Instance.Recycle(this, recycleBack);
}
private IEnumerator recyclePS()
{
while (ps.isPlaying)
yield return null;
ps.Stop(true);
ObjectPoolMgr._Instance.Recycle(this, recycleBack);
}
//主动回收,外部调用
public void Recycle(float waitTime = 0)
{
if (isRecycle)
return;
if (waitCorou != null)
StopCoroutine(waitCorou);
if (waitTime == 0) //立即回收
{
ObjectPoolMgr._Instance.Recycle(this, recycleBack);
}
else if (waitTime > 0) //等待回收
{
if (!gameObject.activeSelf)
ObjectPoolMgr._Instance.Recycle(this, recycleBack);
else
{
if (ps != null)
ps.Stop();
waitCorou = StartCoroutine(recycleWaitTime(waitTime));
}
}
}
//添加回收的回调方法
public void AddRecycleBack(ObjectPoolMgr.RecycleBack back)
{
recycleBack += back;
}
//移除回收的回调
public void RemoveRecycleBack(ObjectPoolMgr.RecycleBack back)
{
recycleBack -= back;
}
//删除回调
public void DelRecycleBack()
{
recycleBack = null;
}
}
对象池负责实例化对象,存取等操作。抽象父类,不同对象池可能会有不同其他操作,但是都需要有初始化,获取回收操作。生成的实例对象存入队列。
using UnityEngine;
using System.Collections;
using System;
//对象池的父类
public class ObjectPool : MonoBehaviour
{
protected SourceObject preSource = null; //配置的资源信息
protected Queue queue = new Queue();//用来保存池中对象
//public int nowCount = 0; //当前池中对象,测试用*******************************************************
//对象池初始化
public virtual void Init(SourceObject source)
{
preSource = source;
if (preSource.prefab == null)
Debug.LogError("初始化对象池失败,预设体为null => " + preSource.sourceName.ToString());
for (int i = 0; i < preSource.preAllocCount; i++)
{
//实例化
GameObject returnObj = Instantiate(preSource.prefab, new Vector3(0, 0, 0), Quaternion.identity) as GameObject;
returnObj.name = preSource.sourceName;
PrefabInfo pre = null;
if (preSource.scriptType != null)
pre = returnObj.AddComponent(preSource.scriptType) as PrefabInfo;
else
pre = returnObj.AddComponent();
pre.Init(preSource.sourceName);
queue.Enqueue(pre);//入队,可进行reset
returnObj.SetActive(false); //不显示
returnObj.transform.SetParent(transform, true);
}
//nowCount = queue.Count;
}
public virtual PrefabInfo alloc(float lifetime)
{
//使用PrefabInfo脚本保存returnObj的一些信息
PrefabInfo info = null;
if (queue.Count > 0)
{
//池中有待分配对象
info = (PrefabInfo)queue.Dequeue();//分配
}
else
{
//池中没有对象了,实例化一个
GameObject returnObj = Instantiate(preSource.prefab, new Vector3(0, 0, 0), Quaternion.identity) as GameObject;
if (preSource.scriptType != null)
info = returnObj.AddComponent(preSource.scriptType) as PrefabInfo;
else
info = returnObj.AddComponent();
info.Init(preSource.sourceName);
returnObj.transform.SetParent(transform, true);
returnObj.SetActive(false);//防止挂在returnObj上的脚本自动开始执行
}
info.lifetime = lifetime;
info.isRecycle = false;
info.gameObject.SetActive(true); //显示
ObjectPoolMgr._Instance.AddPrefabInfo(info); //保存
return info;
}
public virtual void recycle(PrefabInfo obj)
{
//待分配对象已经在对象池中
if (queue.Contains(obj))
{
Debug.LogWarning("the obj " + obj.name + " be recycle twice!");
return;
}
if (queue.Count >= preSource.preAllocCount + preSource.autoIncreaseCount)
{
Destroy(obj.gameObject);//当前池中object数量已满,直接销毁
}
else
{
queue.Enqueue(obj);//入队,并进行reset
obj.transform.SetParent(transform, true);
obj.gameObject.SetActive(false);
}
//nowCount = queue.Count;
}
}
管理者
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System;
///
/// 资源对象,对象池中分配的
///
[Serializable]
public class SourceObject
{
public string sourceDirect; //资源路径
public string sourceName; //资源的名称
public GameObject prefab;//prefab引用
public int preAllocCount = 8;//初始化时预分配对象数量
public int autoIncreaseCount = 8;//池中可增加对象数量
public Type scriptType = null; //对象挂载的脚本名称,反射获取
}
public class ObjectPoolMgr : MonoBehaviour
{
private static ObjectPoolMgr instance = null;
public static ObjectPoolMgr _Instance
{
get
{
return instance;
}
}
private Dictionary DictPool = new Dictionary(); //对象池字典
public List activeList = new List(); //从对象池中分配显示的对象
public delegate void RecycleBack(); //回收前的操作
// Use this for initialization
public IEnumerator Init()
{
instance = this;
////初始化玩家模型
//SourceObject sourceInfo = new SourceObject()
//{
// sourceDirect = "Prefabs/Model/",
// sourceName = "Player01",
// preAllocCount = 0,
// autoIncreaseCount = 0,
// scriptType = typeof(AnimatorCallBack),
//};
//yield return StartCoroutine(InitPool(sourceInfo));
yield return null;
}
////初始化场景跳板对象池
//public IEnumerator InitBoardPool(SceneData data)
//{
// Debug.Log("初始化跳板");
// SourceObject sourceInfo = null;
// for (int i = 0; i < data.boardIDs.Length; i++)
// {
// int boardId = data.boardIDs[i];
// BoardData item = GameDataManager.localData.boardDataBase.GetDataByID(boardId);
// sourceInfo = new SourceObject()
// {
// sourceDirect = data.GetBoardPath (),
// sourceName = item.model,
// preAllocCount = 2,
// autoIncreaseCount = 2,
// scriptType = typeof(BoardItem),
// };
// yield return StartCoroutine(InitPool(sourceInfo));
// }
//}
///
/// 初始化资源对象池
///
///
private IEnumerator InitPool(SourceObject sourceObj)
{
//加载预设对象
if (sourceObj.prefab == null)
{
var loadOperation = AssetsManager._Instance.LoadAssetAsync(sourceObj.sourceDirect, sourceObj.sourceName, true, null, LoadAssetMode.Sync);
yield return loadOperation;
sourceObj.prefab = loadOperation.GetAsset();
}
GameObject poolObj = new GameObject(sourceObj.sourceName + "Pool");
poolObj.transform.SetParent(transform, true);
ObjectPool pool = null;
Type t = Type.GetType(sourceObj.sourceName + "ObjectPool"); //获取特殊的对象池
if (t != null)
pool = (ObjectPool)poolObj.AddComponent(t);
else
pool = poolObj.AddComponent();
if (DictPool.ContainsKey(sourceObj.sourceName))
Debug.Log("存在相同的对象池==>>" + sourceObj.sourceName);
else
{
pool.Init(sourceObj);
DictPool.Add(sourceObj.sourceName, pool);
}
}
///
/// 从对象池申请对象的重载
///
/// 对象id
/// 位置信息
/// 旋转
/// 活跃时间
///
public PrefabInfo Alloc(string sourceName, Vector3 pos, Quaternion rot, float lifetime = 0)
{
PrefabInfo info = Alloc(sourceName, lifetime);
if (info != null)
{
info.transform.position = pos;
info.transform.rotation = rot;
}
else
Debug.LogError("无法从对象池获取=>" + sourceName);
return info;
}
///
/// 从对象池申请对象的重载
///
///
/// lifeTime > 0:lifeTime秒后调用recycle方法回收自己。lifeTime = 0: 不自动回收对象,需游戏主动调用recycle回收。lifeTime< 0: 返回值null。
///
public PrefabInfo Alloc(string sourceName, float lifetime = 0)
{
//根据传入type取出或创建对应类型对象池
ObjectPool subPool = _getpool(sourceName);
//从对象池中取一个对象返回
PrefabInfo returnPre = null;
if (subPool != null)
returnPre = subPool.alloc(lifetime);
return returnPre;
}
//回收对象
public void Recycle(PrefabInfo recyclePre, RecycleBack back = null)
{
if (back != null)
{
back.Invoke();
}
recyclePre.DelRecycleBack();
recyclePre.isRecycle = true;
if (string.IsNullOrEmpty(recyclePre.sourceName))
Destroy(recyclePre.gameObject); //直接销毁
else
{
activeList.Remove(recyclePre); //存活对象列表中移除
ObjectPool returnPool = _getpool(recyclePre.sourceName);
if (returnPool != null)
returnPool.recycle(recyclePre);
else if(recyclePre != null)
Destroy(recyclePre.gameObject);
}
}
public void Recycle(GameObject obj)
{
Recycle(obj.GetComponent());
}
ObjectPool _getpool(string sourceName)
{
ObjectPool returnPool = null;
if (!DictPool.TryGetValue(sourceName, out returnPool))
{
Debug.LogError("不存在对象池==>>" + sourceName);
}
return returnPool;
}
//分配的对象要保存
public void AddPrefabInfo(PrefabInfo pre)
{
activeList.Add(pre);
}
//回收所有对象
public void RecycleAll()
{
PrefabInfo[] prefabs = activeList.ToArray(); //避免回收时从列表中移除,导致列表遍历出现问题
for (int i = 0; i < prefabs.Length; i++)
{
if (!prefabs[i].isRecycle)
prefabs[i].Recycle();
}
activeList.Clear();
}
//移除对象池
public void RecyclePool(string sourceName)
{
ObjectPool pool = _getpool(sourceName);
if (pool != null)
{
DictPool.Remove(sourceName);
Destroy(pool.gameObject);
}
}
}