【对象池接口】
根据对象池所需要的数据和操作,先定义基本的接口
public interface IObjectPool : ICountable, IShrinkable, IDisposable
{
GameObject LendObjectOut(string objectName, Transform parent = null,params object[] extradata);
bool RecycleObject(GameObject go);
}
操作方法为借出对象和回收对象。
借出对象时要传入对象名字,标识想借出哪个对象;parent表示要借出的这个对象的父对象是谁;同时还有个缺省的参数数组。
【对象池基类】
要统计的关键数据是生成的实例对象总数,缓存的实例对象总数,可缓存的实例对象总数。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
namespace Cache
{
public interface IObjectPool : ICountable, IShrinkable, IDisposable
{
GameObject LendObjectOut(string objectName, Transform parent = null,params object[] extradata);
bool RecycleObject(GameObject go);
}
public class ObjectPoolBase : IObjectPool
{
/// <summary>
/// 生成的实例对象总数
/// </summary>
public int TotalCount { get; protected set; }
/// <summary>
/// 缓存的实例对象总数
/// </summary>
public int CachedCount { get; protected set; }
/// <summary>
/// 可缓存的实例对象容量
/// </summary>
public virtual int TotalCapcity { get; protected set; }
protected ICache poolCache;
/// <summary>
/// 对象池名字
/// </summary>
protected string poolName;
/// <summary>
/// 对象池容量大小
/// </summary>
protected int capacity;
protected Action<bool> onlendObjectOut;
protected Action<bool> onRecycleObject;
public virtual int Capacity()
{
return poolCache.Capacity();
}
public virtual int Count()
{
return poolCache.Count();
}
public virtual void Dispose()
{
poolCache.Dispose();
}
public virtual bool Shrink(ShrinkStrategy shrinkStrategy, float percent, int count, bool weedout)
{
return poolCache.Shrink(shrinkStrategy, percent, count, weedout);
}
public virtual GameObject LendObjectOut(string objectName, Transform parent = null, params object[] extradata)
{
return null;
}
public virtual bool RecycleObject(GameObject go)
{
return false;
}
}
}
【管理单个源对象的实例对象的对象池】
我们知道一个对象池里的所有对象都是某个源对象的实例对象,也即调用go = UnityEngine.Object.Instantiate(SourceGo,parent)时,对象池里存放的是一系列go,而Source是我们说的源对象,这个源对象应该通过加载来获取。对象池管理的是实例对象,而不是源对象,两者要分开管理。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
namespace Cache
{
public class SingleObjectPool:ObjectPoolBase
{
private FIFO<GameObject> _poolCache;
private ExpansionStrategy expansionStrategy;
//重写可缓存实例对象的get方法,其在缩容时其会改变
public override int TotalCapcity { get => _poolCache.Capacity(); protected set => TotalCapcity = value; }
public SingleObjectPool(int capacity,string poolName, ExpansionStrategy expansionStrategy = ExpansionStrategy.NONE, Action<bool> onlendObjectOut = null, Action<bool> onRecycleObject = null)
{
poolCache = new FIFO<GameObject>(capacity, expansionStrategy, OnWeedOut);
_poolCache = poolCache as FIFO<GameObject>;
this.capacity = capacity;
this.poolName = poolName;
this.expansionStrategy = expansionStrategy;
this.onlendObjectOut = onlendObjectOut;
this.onRecycleObject = onRecycleObject;
}
public override GameObject LendObjectOut(string objectName,Transform parent = null, params object[] extradata)
{
if(string.IsNullOrEmpty(objectName))
return null;
if (!objectName.Equals(poolName))//如果要借出的物体名字和当前对象池名字不同,说明不能从当前对象池中借出对象
return null;
GameObject go = null;
if(_poolCache.Get(out go))//先从池子里面获取
{
CachedCount--;//缓存对象减少
onlendObjectOut?.Invoke(false);
if(parent != null)
go.transform.SetParent(parent);
return go;
}
//没有就实例化一个,获取一个源对象来实例化
go = UnityEngine.Object.Instantiate(SourceGameObjectMap.GetSourceGameObject(objectName),parent);
if (go != null)
{
TotalCount++;//实例对象增加
onlendObjectOut?.Invoke(true);
}
return go;
}
public override bool RecycleObject(GameObject go)
{
if(_poolCache.Put(go))
{
CachedCount++;//缓存对象增加
onRecycleObject?.Invoke(false);
return true;
}
return false;
}
protected void OnWeedOut(GameObject go)//如果淘汰则销毁
{
if (go == null)
return;
go.transform.SetParent(null); //防止因为Destroy慢一帧依然被GetComponentsInChildren获取到
GameObject.Destroy(go);
TotalCount--;//销毁时,缓存的和生成的实例对象数量都减小
CachedCount--;
onRecycleObject?.Invoke(true);
}
}
}
【源对象的管理】
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace Cache
{
public class SourceGameObjectMap
{
public static Dictionary<string, GameObject> map = new Dictionary<string, GameObject>();
public static GameObject GetSourceGameObject(string objectName)
{
if(map.TryGetValue(objectName, out GameObject go))
{
return go;
}
go = Resources.Load<GameObject>(objectName);//先简单的用Resources.Load,可以自己改为用AB或AA
map.Add(objectName, go);
return go;
}
public static bool UnlaodSourceGameObject(string objectName)
{
if(map.TryGetValue(objectName, out GameObject go))
{
map.Remove(objectName);
Resources.UnloadAsset(go);
return true;
}
return false;
}
}
}