内存池思想:创建对象时,先检查内存池中是否有缓存对象,如果没有再创建新的。 删除对象时,不立即销毁,缓存一段时间,避免重复创建,提升执行效率,用空间换时间的做法。常用怪、NPC、技能特效、血条等。
基本功能:保存,获取,智能删除。
实现方式
基本对象
public class PoolItem
{
public string Name;//文件名+ID作为关键字 因为怪等会同时存在多个
public GameObject Obj;
public bool IsFree = false;
public float RecycleTime;//时间戳,被回收时的时间
public bool IsUpdated=false; //Destroy在update后执行,所以回收的对象在一次update后可以使用
public bool IsForever=false;//是否持久存在,如玩家血条,不需要删除
public PoolItem()
{
Name = "";
Obj = null;
IsFree = false;
RecycleTime = 0;
IsUpdated = false;
IsForever = false;
}
public PoolItem(string name,GameObject obj,bool forever)
{
Name = name;
Obj = obj;
IsFree = true;
RecycleTime = Time.fixedTime;
IsUpdated = false;
IsForever = forever;
}
public bool CanUse //判断是否可以使用,更新过一次的才能用
{
get { return IsFree && IsUpdated; }
}
public bool CanDel //判断当前对象是否可以删除,超过一定时间没使用的删除
{
get { return !IsForever && IsFree && (Time.fixedTime - RecycleTime > 30); }
}
}
执行添加、删除操作
private List<PoolItem> _itemList = new List<PoolItem>();
private void _delItem(int index, bool immediate = false) //真正删除对象 只在这一个地方执行
{
if (immediate)
DestroyImmediate(_itemList[index].Obj);
else
DestroyObject(_itemList[index].Obj);
_itemList.RemoveAt(index);
}
private void _addItemList(PoolItem item) //添加对象
{
_itemList.Add(item);
}
获取缓存对象
//获取缓存对象 创建时先检查是否有可用缓存
public PoolItem GetFreeItem(string filename)
{
for (int i = 0; i < _itemList.Count; i++)
{
PoolItem item = _itemList[i];
if (item.CanUse && item.Name.IndexOf(filename, System.StringComparison.Ordinal) >= 0)
{
item.IsFree = false;
return item;
}
}
return null;
}
保存缓存对象
//回收对象 代替删除
public void RecycleItem(string effname, GameObject gb, bool isForever = false)
{
PoolItem item = _getPoolItem(gb) ?? new PoolItem(effname,gb,isForever);
_addItemList(item);
gb.transform.parent = transform;//调整节点
gb.SetActive(false);
}
private PoolItem _getPoolItem(GameObject gb)
{
PoolItem item = null;
for (int i = 0; i < _itemList.Count; i++)
{
var item2 = _itemList[i];
if (item2.Obj == gb)
{
item = item2;
break;
}
}
return item;
}
根据时间删除不需要的缓存对象
void Update()
{
for(int i =0;i<_itemList.Count;)
{
var item=_itemList[i];
item.IsUpdated=true;
if(item.CanDel)
_delItem(i);
else
i++;
}
}
特殊条件释放所有不用资源
//释放所有资源 一般在切换场景时操作
public void UnloadAllFree()
{
for (int i = 0; i < _itemList.Count; )
{
var item = _itemList[i];
if (item.IsFree)
_delItem(i, true);
else
i++;
}
}
对perfab的处理:加载出来的资源很多需要在使用时动态改变一些参数,或设置显隐等,回收时需要根据实际情况重置。
这样一个简单的内存池功能就实现了,实际应用中还可以控制不同对象缓存时间,设置优先级控制大小等。