【对象的分类】
在整个游戏过程中,对象非常多,可以根据一定的标准将对象分类:例如这些对象都属于UI、那些对象属于地形、还有些对象属于角色等等;有些对象只在第一阶段出现、有些只在第二阶段出现,有些只在第三阶段出现等等;有些对象属于某个剧情或任务中的;有些对象处于某个地点或范围等。
如果我们希望对游戏中的所有实例对象做一个管理,那么做一个复杂嵌套的超级对象池来管理,这个对象池内部如何嵌套的,也即如何将对象分类,是需要根据游戏,也即业务来做的。我们需要事先考虑好,这也反映出是否可以整体把握游戏。
在本文中,将对象做一个不同类别和不同阶段的分类,这里认为不同阶段里有不同类型的对象,也可以做不同类型的对象处于不同的阶段,代码基本上都大同小异,都是以前文的管理单个实例对象的对象池与管理多个实例的对象池为基础的。
【管理多类实例对象池的实现】
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
namespace Cache
{
public enum ObjectType
{
Common = 0,
UI = 1,
Role = 2,
Effect = 3,
Terrain = 4,
Collider = 5,
Camera = 6,
Special
}
public class ObjectTypePool : ObjectPoolBase
{
private Cache<ObjectType, MultiObjectPool> _poolCache;//ObjectType本质是string,只不过数量少些用枚举,而不是MultiObjectPool中用string
private Dictionary<int, ObjectType> lentInstance2ObjectType = new Dictionary<int, ObjectType>();
private Dictionary<string, ObjectType> nameMap = new Dictionary<string, ObjectType>();
public ObjectTypePool(int capacity, string poolName, CacheWeedOutStrategy cacheWeedOutStrategy, Action<bool> onlendObjectOut = null, Action<bool> onRecycleObject = null) : base(capacity, poolName, onlendObjectOut, onRecycleObject)
{
poolCache = new Cache<ObjectType, MultiObjectPool>(cacheWeedOutStrategy, capacity, OnWeedOut);
_poolCache = poolCache as Cache<ObjectType, MultiObjectPool>;
foreach (ObjectType item in Enum.GetValues(typeof(ObjectType)))
{
nameMap.Add(item.ToString(), item);
}
}
public ObjectTypePool(PoolInfo poolInfo, Action<bool> onlendObjectOut = null, Action<bool> onRecycleObject = null) : base(poolInfo, onlendObjectOut, onRecycleObject)
{
if (poolInfo != null)
{
foreach (ObjectType item in Enum.GetValues(typeof(ObjectType)))
{
nameMap.Add(item.ToString(), item);
}
if (poolInfo.poolType == PoolType.ObjectType)
{
poolCache = new Cache<ObjectType, MultiObjectPool>(poolInfo.cacheWeedOutStrategy, poolInfo.capacity, OnWeedOut);
_poolCache = poolCache as Cache<ObjectType, MultiObjectPool>;
//初始化子对象池
foreach (var item in poolInfo.subPoolInfo)
{
var subPool = new MultiObjectPool(item, OnLendObjectOut, OnRecycleObject);
_poolCache.Put(nameMap[subPool.poolName], subPool);
TotalCapcity += subPool.TotalCapcity;
}
//使用默认的池子设置
for (int i = poolInfo.subPoolInfo.Count; i < poolInfo.subPoolCount; i++)
{
var subPool = new MultiObjectPool(poolInfo.defaultSubPoolInfo, OnLendObjectOut, OnRecycleObject);
_poolCache.Put(nameMap[subPool.poolName], subPool);
TotalCapcity += subPool.TotalCapcity;
}
}
}
}
public override GameObject LendObjectOut(string objectName, Transform parent = null, object[] extradata = null)
{
GameObject go = null;
if (string.IsNullOrEmpty(objectName))
return null;
MultiObjectPool multiObjectPool = null;
ObjectType objectType;//要将对象类型的参数传进来
if(Enum.TryParse<ObjectType>(extradata[0].ToString(),out objectType))
{
if (_poolCache.Get(objectType, out multiObjectPool))
{
go = multiObjectPool.LendObjectOut(objectName, parent);
}
}
if(go != null)
lentInstance2ObjectType[go.GetInstanceID()] = objectType;
return go;
}
public override bool RecycleObject(GameObject go)
{
if (go == null)
return false;
if (!lentInstance2ObjectType.ContainsKey(go.GetInstanceID()))
return false;
MultiObjectPool pool;
if (_poolCache.Get(lentInstance2ObjectType[go.GetInstanceID()], out pool))
{
if (pool.RecycleObject(go))
{
lentInstance2ObjectType.Remove(go.GetInstanceID());
return true;
}
}
return false;
}
private void OnWeedOut(MultiObjectPool multiObjectPool)
{
TotalCount -= multiObjectPool.TotalCount;
CachedCount -= multiObjectPool.CachedCount;
TotalCapcity -= multiObjectPool.TotalCapcity;
multiObjectPool.Dispose();
}
private void OnLendObjectOut(bool instantiated)
{
if (instantiated)
TotalCount++;
else
CachedCount--;
onlendObjectOut?.Invoke(instantiated);
}
private void OnRecycleObject(bool destroyed)
{
if (destroyed)
{
TotalCount--;
CachedCount--;
}
else
CachedCount++;
onRecycleObject?.Invoke(destroyed);
}
}
}
【管理多阶段实例的对象池】
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
namespace Cache
{
public enum StageType
{
FirstStage = 1,
SecondStage,
ThirdStage,
FourthStage,
FifthStage,
}
public class StageObjectPool : ObjectPoolBase
{
private Cache<StageType, ObjectTypePool> _poolCache;
private Dictionary<int, StageType> lentInstance2StageType = new Dictionary<int, StageType>();
private Dictionary<string, StageType> nameMap = new Dictionary<string, StageType>();
public StageObjectPool(int capacity, string poolName, CacheWeedOutStrategy cacheWeedOutStrategy, Action<bool> onlendObjectOut = null, Action<bool> onRecycleObject = null) : base(capacity, poolName, onlendObjectOut, onRecycleObject)
{
poolCache = new Cache<StageType, ObjectTypePool>(cacheWeedOutStrategy, capacity, OnWeedOut);
_poolCache = poolCache as Cache<StageType, ObjectTypePool>;
foreach (StageType item in Enum.GetValues(typeof(StageType)))
{
nameMap.Add(item.ToString(), item);
}
}
public StageObjectPool(PoolInfo poolInfo, Action<bool> onlendObjectOut = null, Action<bool> onRecycleObject = null) : base(poolInfo, onlendObjectOut, onRecycleObject)
{
if (poolInfo != null)
{
foreach (StageType item in Enum.GetValues(typeof(StageType)))
{
nameMap.Add(item.ToString(), item);
}
if (poolInfo.poolType == PoolType.StageType)
{
poolCache = new Cache<StageType, ObjectTypePool>(poolInfo.cacheWeedOutStrategy, poolInfo.capacity, OnWeedOut);
_poolCache = poolCache as Cache<StageType, ObjectTypePool>;
//初始化子对象池
foreach (var item in poolInfo.subPoolInfo)
{
var subPool = new ObjectTypePool(item, OnLendObjectOut, OnRecycleObject);
_poolCache.Put(nameMap[subPool.poolName], subPool);
TotalCapcity += subPool.TotalCapcity;
}
//使用默认的池子设置
for (int i = poolInfo.subPoolInfo.Count; i < poolInfo.subPoolCount; i++)
{
var subPool = new ObjectTypePool(poolInfo.defaultSubPoolInfo, OnLendObjectOut, OnRecycleObject);
_poolCache.Put(nameMap[subPool.poolName], subPool);
TotalCapcity += subPool.TotalCapcity;
}
}
}
}
public override int Capacity()
{
return poolCache.Capacity();
}
public override int Count()
{
return poolCache.Count();
}
public override GameObject LendObjectOut(string objectName, Transform parent = null, object[] extradata = null)
{
GameObject go = null;
if (string.IsNullOrEmpty(objectName))
return null;
StageType stageType;//要将阶段类型和对象类型也传进来
if (Enum.TryParse<StageType>(extradata[0].ToString(), out stageType))
{
ObjectType objectType;
if(Enum.TryParse<ObjectType>(extradata[0].ToString(), out objectType))
{
ObjectTypePool objectTypePool = null;
if (_poolCache.Get(stageType, out objectTypePool))
{
go = objectTypePool.LendObjectOut(objectName, parent,objectType);
}
}
}
if (go != null)
lentInstance2StageType[go.GetInstanceID()] = stageType;
return go;
}
public override bool RecycleObject(GameObject go)
{
if (go == null)
return false;
if (!lentInstance2StageType.ContainsKey(go.GetInstanceID()))
return false;
ObjectTypePool pool;
if (_poolCache.Get(lentInstance2StageType[go.GetInstanceID()], out pool))
{
if (pool.RecycleObject(go))
{
lentInstance2StageType.Remove(go.GetInstanceID());
return true;
}
}
return false;
}
private void OnWeedOut(ObjectTypePool objectTypePool)
{
TotalCount -= objectTypePool.TotalCount;
CachedCount -= objectTypePool.CachedCount;
TotalCapcity -= objectTypePool.TotalCapcity;
objectTypePool.Dispose();
}
private void OnLendObjectOut(bool instantiated)
{
if (instantiated)
TotalCount++;
else
CachedCount--;
onlendObjectOut?.Invoke(instantiated);
}
private void OnRecycleObject(bool destroyed)
{
if (destroyed)
{
TotalCount--;
CachedCount--;
}
else
CachedCount++;
onRecycleObject?.Invoke(destroyed);
}
}
}
【需要管理类吗】
现在有很多类型的对象池,正如我们需要用对象池去管理很多实例一般,我们需要一个对象池管理类来管理很多的对象池。回顾一下,本文的多类实例的对象池和对阶段实例的对象池也是对一系列相同的对象进行了管理。