UFL3-4——缓存池增加缓存对象种类
缓存池模块(数据结构类、逻辑类)优化 主要目的
我们目前实现的缓存池,主要是针对场景上的GameObject
对象的,我们只能对场景上的对象进行缓存池功能处理
但是在游戏开发中,还会存在大量的不需要挂载到场景上的实例化对象
比如一些数据结构类、逻辑类,它们并不依附于场景上的对象,而仅仅是被引用
举例:
一个自定义数据结构类,TestData t = new TestData();
当我们不使用它时,往往会将其置空,t = null;
下次又要使用时,再new
,t = new TestData();
那么对于一些频繁使用的数据结构类或逻辑类,这样做也会产生大量的垃圾
因此我们完全可以修改缓存池模块,让其也支持对不挂载的类对象也进行复用
说人话:
缓存池模块(数据结构类、逻辑类)优化 主要目的是让缓存池支持回收复用不继承MonoBehaviour
(不挂载GameObject
)的类对象
缓存池模块(数据结构类、逻辑类)优化 制作思路
关键点:
-
池子容器父类里式替换父类装子类
1 2 3 4
|
public abstract class PoolObjectBase { }
|
-
池子容器子类泛型类确定对象类型
1 2 3 4 5 6 7 8
|
public class PoolObject<T> : PoolObjectBase where T : class { public Queue<T> poolObjs = new Queue<T>(); }
|
-
对象父接口,用于实现重置数据方法
1 2 3 4 5 6 7 8 9 10
|
public interface IPoolObject { void ResetInfo(); }
|
注意:由于这些自定义数据或逻辑类中可能有对其他内容的引用,因此需要让其有一个重置数据的方法,在压入池子时重置数据
实现思路:
-
修改缓存池管理器 PoolManager
-
添加一个新池子容器,专门用来记录不继承 MonoBehaviour
(不挂载GameObject
)的类对象
1 2
| private Dictionary<string, PoolObjectBase> poolObjectDic = new Dictionary<string, PoolObjectBase>();
|
-
提供专门的方法供外部使用
-
从池子中获取对象的方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
|
public T GetObj<T>(string nameSpace = "") where T : class, IPoolObject, new() { string poolName = nameSpace + "_" + typeof(T).Name; if (poolObjectDic.ContainsKey(poolName)) { PoolObject<T> pool = poolObjectDic[poolName] as PoolObject<T>; if (pool.poolObjs.Count > 0) { T obj = pool.poolObjs.Dequeue(); return obj; } else { T obj = new T(); return obj; } } else { T obj = new T(); return obj; } }
|
-
压入池子中的方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| public void PushObj<T>(T obj, string nameSpace = "") where T : class, IPoolObject { if (obj == null) return; string poolName = nameSpace + "_" + typeof(T).Name; PoolObject<T> pool; if (poolObjectDic.ContainsKey(poolName)) { pool = poolObjectDic[poolName] as PoolObject<T>; } else { pool = new PoolObject<T>(); poolObjectDic.Add(poolName, pool); } obj.ResetInfo(); pool.poolObjs.Enqueue(obj); }
|
-
清空池子容器的方法
直接修改原来的方法即可
1 2 3 4 5 6 7 8 9
|
public void ClearPool() { poolDic.Clear(); poolObjectDic.Clear(); poolObj = null; }
|
使用示例
声明一个由缓存池管理的类
1 2 3 4 5 6 7 8 9 10 11 12 13
| public class TestData : IPoolObject { public int i; public string str; public object obj;
public void ResetInfo() { i = 0; str = ""; obj = null; } }
|
对缓存池特定位置打断点
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| public class Main : MonoBehaviour { private TestData data;
void Update() { if (Input.GetKeyDown(KeyCode.G)) { data = PoolManager.Instance.GetObj<TestData>(); data.i = 11; data.obj = new object(); data.str = "123"; }
if (Input.GetKeyDown(KeyCode.P)) { PoolManager.Instance.PushObj<TestData>(data); data = null; } } }
|
通过缓存池获取对象,再通过将对象压入到缓存池内,通过断点调试,观察代码执行顺序,以及缓存池内对象数量变化
具体代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255
| using System.Collections; using System.Collections.Generic; using UnityEngine;
public class PoolData { private GameObject poolObj; private Stack<GameObject> dataStack = new Stack<GameObject>(); private int maxNum; private List<GameObject> usedList = new List<GameObject>(); public int Count => dataStack.Count; public int UsedCount => usedList.Count;
public bool NeedCreate => usedList.Count < maxNum;
public PoolData(GameObject poolRootObj, string poolName, GameObject usedObj) { if (PoolManager.isOpenLayout) { poolObj = new GameObject(poolName); poolObj.transform.SetParent(poolRootObj.transform); } PushUsedList(usedObj); PoolObj obj = usedObj.GetComponent<PoolObj>(); if (obj == null) { Debug.LogError("请为缓存池功能的预设体对象挂载PoolObj脚本,用于设置数量上限"); return; } this.maxNum = obj.maxNum; }
public GameObject Pop() { GameObject obj; if (Count > 0) { obj = dataStack.Pop(); usedList.Add(obj); } else { obj = usedList[0]; usedList.RemoveAt(0); usedList.Add(obj); } obj.SetActive(true); if (PoolManager.isOpenLayout) obj.transform.SetParent(null); return obj; }
public void Push(GameObject obj) { obj.SetActive(false); if (PoolManager.isOpenLayout) obj.transform.SetParent(poolObj.transform); dataStack.Push(obj); usedList.Remove(obj); }
public void PushUsedList(GameObject obj) { usedList.Add(obj); } }
public abstract class PoolObjectBase { }
public class PoolObject<T> : PoolObjectBase where T : class { public Queue<T> poolObjs = new Queue<T>(); }
public interface IPoolObject { void ResetInfo(); }
public class PoolManager : BaseManager<PoolManager> { private Dictionary<string, PoolData> poolDic = new Dictionary<string, PoolData>(); private Dictionary<string, PoolObjectBase> poolObjectDic = new Dictionary<string, PoolObjectBase>();
private GameObject poolObj;
public static bool isOpenLayout = true;
private PoolManager() { }
public GameObject GetObj(string name) { if (poolObj == null && isOpenLayout) poolObj = new GameObject("Pool");
GameObject obj; if (!poolDic.ContainsKey(name) || (poolDic[name].Count == 0 && poolDic[name].NeedCreate)) { obj = GameObject.Instantiate(Resources.Load<GameObject>(name)); obj.name = name; if (!poolDic.ContainsKey(name)) poolDic.Add(name, new PoolData(poolObj, name, obj)); else poolDic[name].PushUsedList(obj); } else { obj = poolDic[name].Pop(); } return obj; }
public T GetObj<T>(string nameSpace = "") where T : class, IPoolObject, new() { string poolName = nameSpace + "_" + typeof(T).Name; if (poolObjectDic.ContainsKey(poolName)) { PoolObject<T> pool = poolObjectDic[poolName] as PoolObject<T>; if (pool.poolObjs.Count > 0) { T obj = pool.poolObjs.Dequeue(); return obj; } else { T obj = new T(); return obj; } } else { T obj = new T(); return obj; } }
public void PushObj(GameObject obj) {
poolDic[obj.name].Push(obj); }
public void PushObj<T>(T obj, string nameSpace = "") where T : class, IPoolObject { if (obj == null) return; string poolName = nameSpace + "_" + typeof(T).Name; PoolObject<T> pool; if (poolObjectDic.ContainsKey(poolName)) { pool = poolObjectDic[poolName] as PoolObject<T>; } else { pool = new PoolObject<T>(); poolObjectDic.Add(poolName, pool); } obj.ResetInfo(); pool.poolObjs.Enqueue(obj); }
public void ClearPool() { poolDic.Clear(); poolObjectDic.Clear(); poolObj = null; } }
|