对象池能让创建对象的cpu开销减少,也可以让内存控制再一定的数量上,是大量角色或物体创建移除的比较合适的解决方案。但很多用的是针对指定类型或场景下使用的对象池,很难做到通用。最近研究到,有这样一套对象池的解决方案。
这套解决方案同样会分为获取Get,移除Release后回收。只是可以自定义我们需要获得的对象类型。
代码如下:
//Game 中对象池ObjectPool
//需要自定义TypeOp.ObjCreator来创建对象
//需要自定义TypeOp.ObjClear来清理对象
//#define OBJECT_POOL_DEBUG
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
namespace QMGame
{
public static class ObjectPool
{
private static Dictionary<Type, object> poolDictionary = new Dictionary<Type, object>();
const int TotalNum = 30;
public static void Clear()
{
poolDictionary.Clear();
}
/// <summary>
/// 如果对象池中有则返回对象池中的,不然就Activator.CreateInstance
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static T Get<T>()
{
Type t = typeof(T);
object pooledObjects;
//1.先查看对象池中是否存在可用的指定类型对象
if (poolDictionary.TryGetValue(t, out pooledObjects))
{
List<object> lstObjects = pooledObjects as List<object>;
if (lstObjects.Count > 0)
{
//获取可用对象,并且再对象池中移除掉
object obj = lstObjects[lstObjects.Count - 1];
lstObjects.RemoveAt(lstObjects.Count - 1);
return (T)obj;
}
}
//没找到则需要去创建新对象
return (T)NewObject(t);
}
private static object NewObject(Type t)
{
PoolObject po = null;
//2.我们指定的类型中是否包括了我们指定的类型
if (ObjectPoolHelper.objectCreator.TryGetValue(t, out po))
{
//有则创建,创建的方法再ObjectPoolHelper的creator中执行
if (po.creator != null)
return po.creator();
}
//3.实在连指定类型中都没有,说明项目中没有指定该类型为需要用对象池的类型,则直接创建。
return Activator.CreateInstance(t);
}
/// <summary>
/// 外部执行可以释放一个对象到对象池了
/// </summary>
/// <param name="obj"></param>
public static void Return(object obj)
{
if (obj == null) { return; }
object pooledObjects;
Type t = obj.GetType();
PoolObject po = null;
//对象池指定类型如果包括这个类型则需要在对象池中释放
if (ObjectPoolHelper.objectCreator.TryGetValue(t, out po))
{
//执行移除的方法,具体执行也是在我们指定的类型中
if (po.clear != null)
{
po.clear(obj);
}
}
else
{
//LogWarning("未配置对象操作委托,请按照规范使用ObjectgPool");
return;
}
//该类型的对象池中是否包含他
if (poolDictionary.TryGetValue(t, out pooledObjects))
{
List<object> lstObjects = pooledObjects as List<object>;
#if UNITY_EDITOR && OBJECT_POOL_DEBUG
for (int i = 0; i < lstObjects.Count; i++)
{
if (lstObjects[i] == obj)
{
LogWarning("此对象被重复添加到对象池: {0},请检查ObjectPool的使用是否符合规范!", t.ToString());
return;
}
}
#endif
//没有到上限则加上,超过上限则不加入了。对象已经通过clear移除了,这里只是看需不需要加回到对象池中,既然都超过了上限了,就不需要他加入了
if (lstObjects.Count < TotalNum)
lstObjects.Add(obj);
else
{
DebugHelper.LogWarning("对象池中缓存的对象{0}数量超过阈值,请检查对象的创建流程是否使用了对象池", t.ToString());
}
}
else
{
//对象池中不包含这个对象则加入
List<object> lstObjects = new List<object>();
poolDictionary.Add(t, lstObjects);
lstObjects.Add(obj);
}
}
}
}
上面是获取对象和移除对象的相关方法,在正式使用中需要成对使用,才能正常获取和释放。
using System.Collections.Generic;
using UnityEngine;
using System;
using BumperCar;
namespace QMGame
{
public delegate object ObjectCreator();
public delegate void ObjectClear(object obj);
public class PoolObject
{
public ObjectCreator creator;
public ObjectClear clear;
}
public class ObjectPoolHelper
{
public static Dictionary<Type, PoolObject> objectCreator = new Dictionary<Type, PoolObject>()
{
{
//指定List<Actor>类型,然后给他两个方法,一个是创建,我们指定如何创建他。一个移除方法,指定如何移除。这里需要我们手动指定
typeof(List<Actor>),
new PoolObject()
{
creator = delegate {return new List<Actor>(); },
clear = obj =>{
List<Actor> list = obj as List<Actor>;
list.Clear();
}
}
},
{
//指定ChangeForwardCommandData类型,然后给他两个方法,一个是创建,我们指定如何创建他。一个移除方法,指定如何移除。这里需要我们手动指定
typeof(ChangeForwardCommandData),
new PoolObject()
{
creator = () => { return new ChangeForwardCommandData(); },
clear = (obj) => {
ChangeForwardCommandData data = obj as ChangeForwardCommandData;
data.Clear();
}
}
}
};
}
}
上面是指定的类型的对象池。需要手动设定。
使用示例:
来源:CSDN
作者:llsansun
链接:https://blog.csdn.net/llsansun/article/details/103870193