using UnityEngine;
using System.Collections.Generic;
using System;
using System.Collections.ObjectModel;
using System.Linq;
///
/// 泛型对象池的父类,支持活跃对象的查找
///
/// 基类对象池
public abstract class BasePool : MonoBehaviour where BaseClass : MonoBehaviour
{
///
/// 对象池本体
///
protected Dictionary> Pools = new Dictionary>();
///
/// 活跃对象记录表
///
protected Dictionary> ActiveObjectList = new Dictionary>();
///
/// 依据一个原型,返回一个空的可用对象
///
public DerivedClass Get(DerivedClass prefab) where DerivedClass : BaseClass
{
var type = typeof(DerivedClass);
if (!Pools.ContainsKey(type))
{
Pools[type] = new Stack();
ActiveObjectList[type] = new List();
}
DerivedClass obj;
//对象池逻辑
if (Pools[type].Count > 0)
{
obj = (DerivedClass)Pools[type].Pop();
ActiveObjectList[type].Add(obj);
}
else
{
//如果对象池没有对象,则创建一个对象
obj = Instantiate(prefab);
ActiveObjectList[type].Add(obj);
OnCreate(obj);
}
OnGet(obj);
obj.gameObject.SetActive(true);
obj.enabled = true;
return obj;
}
///
/// 回收当前对象
///
public void Release(BaseClass Object)
{
var type = Object.GetType();
//如果字典中没有该类的对象池,则创建一个该类型的对象池
if (!Pools.ContainsKey(type)) Pools[type] = new Stack();
OnRelease(Object);
Object.gameObject.SetActive(false);
Pools[type].Push(Object);
ActiveObjectList[type].Remove(Object);
}
///
/// 该对象是否有被实例化
///
///
///
public bool ContainsObject(BaseClass Object)
{
var type = Object.GetType();
//如果没有该类型的对象池,则返回假
if (!Pools.ContainsKey(type)) return false;
return ActiveObjectList[type].Contains(Object);
}
///
/// 清空对象池
///
///
///
///
public void ClearPool()
{
foreach (var stack in Pools.Values)
{
while (stack.Count > 0)
{
Destroy(stack.Pop().gameObject);
}
}
Pools.Clear();
}
///
/// 返回一个当前类型的只读列表
///
public ReadOnlyCollection GetActiveObjectList() where DerivedClass : BaseClass
{
var type=typeof(DerivedClass);
if (!Pools.ContainsKey(type))
{
ActiveObjectList[type] = new List();
}
//what the fuck ? this code is SHIT!
return ActiveObjectList[type].Cast().ToList().AsReadOnly();
}
///
/// 对指定类型的所有活跃对象执行指定操作
///
/// 要操作的派生类型
/// 要对每个对象执行的操作
/// 是否包含非活跃对象(已回收但未销毁的对象)
public void ForEach(Action action) where DerivedClass : BaseClass
{
var type = typeof(DerivedClass);
// 检查是否有该类型的活跃对象列表
if (!ActiveObjectList.TryGetValue(type, out var list) || list == null) return;
for (int i = list.Count - 1; i >= 0; i--)
{
var item = (DerivedClass)list[i];
action?.Invoke(item);
}
}
///
/// 当对象首次创建时调用
///
protected virtual void OnCreate(BaseClass obj) { }
///
/// 当对象从池中取出时调用
///
protected virtual void OnGet(BaseClass obj) { }
///
/// 当对象回收到池中时调用
///
protected virtual void OnRelease(BaseClass obj) { }
}
/*
首先必须分清楚我们需要的是哪种对象池。
在一个类里面完成所有不同对象池功能的定义是绝对不现实的,这是显而易见的。
但是我们又想实现一定意义上的对象池复用,所以我们需要的其实是一个可重复实例化的对象池。
很容易的得到,这个对象池应该继承与MonoBehaviour,因为其实所有的脚本类其实都继承与这个类。
所以依据里氏转换原则,MonoBehaviour可以被转换为任意我们已有的脚本。
并且可以使用unity相关的API,如SetActive(false)等。
我们的对象仅仅只能在必要时 生成/初始化 但是不同类型的对象完全不一样,为了实现基对象池与限定类型的解耦合,
我们可以采用回调函数的方式,即定义一个Action()类型的的回调函数,并且在每次对象池调用对象时,即刻执行这个Action()
这个Action()既可以是我再子类对象池中覆写的函数,也可以是子类自带的初始化函数
当然采用回调函数的方法未免还是有点大题小做,可以通过仿照生命周期函数的方式,完成基类的定义,
并且,基类不进行实例化,它只可以被继承至子类,以保证安全性,我们必须防止所有的实例共用一个栈的情况发生
理论上是可行的
*/