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()既可以是我再子类对象池中覆写的函数,也可以是子类自带的初始化函数 当然采用回调函数的方法未免还是有点大题小做,可以通过仿照生命周期函数的方式,完成基类的定义, 并且,基类不进行实例化,它只可以被继承至子类,以保证安全性,我们必须防止所有的实例共用一个栈的情况发生 理论上是可行的 */