//删除gameobject 所有从GameObjectPool中 static void DestroyGameObject(this GameObjectPoolComponent self, GameObject inst) { if (self.__instPathCache.TryGetValue(inst, out string path)) { if (self.__goInstCountCache.TryGetValue(path, out int count)) { if (count <= 0) { Log.Error("__goInstCountCache[path] must > 0"); } else { self.__CheckRecycleInstIsDirty(path, inst, () => { GameObject.Destroy(inst); self.__goInstCountCache[path] = self.__goInstCountCache[path] - 1; }); } } } else { Log.Error("DestroyGameObject inst not found from __instPathCache"); } }
//尝试从缓存中获取 public static bool TryGetFromCache(this GameObjectPoolComponent self, string path, out GameObject go) { go = null; if (!self.CheckHasCached(path)) { return(false); } if (self.__instCache.TryGetValue(path, out var cachedInst)) { if (cachedInst.Count > 0) { var inst = cachedInst[cachedInst.Count - 1]; cachedInst.RemoveAt(cachedInst.Count - 1); go = inst; if (inst == null) { Log.Error("Something wrong, there gameObject instance in cache is null!"); return(false); } return(true); } } if (self.__goPool.TryGet(path, out var pooledGo)) { if (pooledGo != null) { var inst = GameObject.Instantiate(pooledGo); self.__goInstCountCache[path] = self.__goInstCountCache[path] + 1; self.__instPathCache[inst] = path; go = inst; return(true); } } return(false); }
//缓存并实例化GameObject static void CacheAndInstGameObject(this GameObjectPoolComponent self, string path, GameObject go, int inst_count) { self.__goPool.Set(path, go); self.__InitGoChildCount(path, go); if (inst_count > 0) { List <GameObject> cachedInst; if (!self.__instCache.TryGetValue(path, out cachedInst)) { cachedInst = new List <GameObject>(); } for (int i = 0; i < inst_count; i++) { var inst = GameObject.Instantiate(go); inst.transform.SetParent(self.__cacheTransRoot); inst.SetActive(false); cachedInst.Add(inst); self.__instPathCache[inst] = path; } self.__instCache[path] = cachedInst; if (!self.__goInstCountCache.ContainsKey(path)) { self.__goInstCountCache[path] = 0; } self.__goInstCountCache[path] = self.__goInstCountCache[path] + inst_count; } }
static async ETTask __CheckAfter(this GameObjectPoolComponent self, string path, GameObject inst) { await TimerComponent.Instance.WaitAsync(2000); if (inst != null && inst.transform != null && self.__CheckInstIsInPool(path, inst)) { var go_child_count = self.__goChildsCountPool[path]; Dictionary <string, int> childsCountMap = new Dictionary <string, int>(); int inst_child_count = self.RecursiveGetChildCount(inst.transform, "", ref childsCountMap); if (go_child_count != inst_child_count) { Log.Error($"go_child_count({ go_child_count }) must equip inst_child_count({inst_child_count}) path = {path} "); foreach (var item in childsCountMap) { var k = item.Key; var v = item.Value; var unfair = false; if (!self.__detailGoChildsCount[path].ContainsKey(k)) { unfair = true; } else if (self.__detailGoChildsCount[path][k] != v) { unfair = true; } if (unfair) { Log.Error($"not match path on checkrecycle = { k}, count = {v}"); } } } } }
//预加载:可提供初始实例化个数 public static async ETTask PreLoadGameObjectAsync(this GameObjectPoolComponent self, string path, int inst_count, Action callback = null) { CoroutineLock coroutineLock = null; try { coroutineLock = await CoroutineLockComponent.Instance.Wait(CoroutineLockType.Resources, path.GetHashCode()); if (self.CheckHasCached(path)) { callback?.Invoke(); } else { var go = await ResourcesComponent.Instance.LoadAsync <GameObject>(path); if (go != null) { self.CacheAndInstGameObject(path, go as GameObject, inst_count); } callback?.Invoke(); } } finally { coroutineLock?.Dispose(); } }
// 初始化inst static void InitInst(this GameObjectPoolComponent self, GameObject inst) { if (inst != null) { inst.SetActive(true); } }
//回收 public static void RecycleGameObject(this GameObjectPoolComponent self, GameObject inst, bool isclear = false) { if (!self.__instPathCache.ContainsKey(inst)) { Log.Error("RecycleGameObject inst not found from __instPathCache"); return; } var path = self.__instPathCache[inst]; if (!isclear) { self.__CheckRecycleInstIsDirty(path, inst, null); inst.transform.SetParent(self.__cacheTransRoot, false); inst.SetActive(false); if (!self.__instCache.ContainsKey(path)) { self.__instCache[path] = new List <GameObject>(); } self.__instCache[path].Add(inst); } else { self.DestroyGameObject(inst); } //self.CheckCleanRes(path); }
static int RecursiveGetChildCount(this GameObjectPoolComponent self, Transform trans, string path, ref Dictionary <string, int> record) { int total_child_count = trans.childCount; for (int i = 0; i < trans.childCount; i++) { var child = trans.GetChild(i); if (child.name.Contains("Input Caret") || child.name.Contains("TMP SubMeshUI") || child.name.Contains("TMP UI SubObject") || /*child.GetComponent<LoopListViewItem2>()!=null || child.GetComponent<LoopGridViewItem>() != null ||*/(child.name.Contains("Caret") && child.parent.name.Contains("Text Area"))) { //Input控件在运行时会自动生成个光标子控件,而prefab中是没有的,所以得过滤掉 //TextMesh会生成相应字体子控件 //TextMeshInput控件在运行时会自动生成个光标子控件,而prefab中是没有的,所以得过滤掉 total_child_count = total_child_count - 1; } else { string cpath = path + "/" + child.name; if (record.ContainsKey(cpath)) { record[cpath] += 1; } else { record[cpath] = 1; } total_child_count += self.RecursiveGetChildCount(child, cpath, ref record); } } return(total_child_count); }
public static GameObject GetCachedGoWithPath(this GameObjectPoolComponent self, string path) { if (self.__goPool.TryOnlyGet(path, out var res)) { return(res); } return(null); }
public static void RecycleUIGameObject <T>(this GameObjectPoolComponent self, T obj, bool isClear = false) where T : Entity { var uiTrans = obj.GetUIComponent <UITransform>(); self.RecycleGameObject(uiTrans.transform.gameObject, isClear); obj.BeforeOnDestroy(); UIEventSystem.Instance.OnDestroy(obj); }
public static GameObject GetGameObject(this GameObjectPoolComponent self, string path) { if (self.TryGetFromCache(path, out var inst)) { self.InitInst(inst); return(inst); } return(null); }
//检测回收的时候是否需要清理资源(这里是检测是否清空 inst和缓存的go) //这里可以考虑加一个配置表来处理优先级问题,一些优先级较高的保留 public static void CheckCleanRes(this GameObjectPoolComponent self, string path) { var cnt = self.__goInstCountCache[path] - (self.__instCache.ContainsKey(path) ? self.__instCache[path].Count : 0); if (cnt == 0 && !self.__persistentPathCache.ContainsKey(path)) { self.__ReleaseAsset(path); } }
static void __CheckRecycleInstIsDirty(this GameObjectPoolComponent self, string path, GameObject inst, Action callback) { if (!self.__IsOpenCheck()) { callback?.Invoke(); return; } inst.SetActive(false); self.__CheckAfter(path, inst).Coroutine(); callback?.Invoke(); }
//--释放asset //--注意这里需要保证外面没有引用这些path的inst了,不然会出现材质丢失的问题 //--不要轻易调用,除非你对内部的资源的生命周期有了清晰的了解 //--@param includePooledGo: 是否需要将预设也释放 //--@param patharray: 需要释放的资源路径数组 public static void CleanupWithPathArray(this GameObjectPoolComponent self, bool includePooledGo = true, List <string> patharray = null) { Debug.Log("GameObjectPool Cleanup "); Dictionary <string, bool> dict_path = null; if (patharray != null) { dict_path = new Dictionary <string, bool>(); for (int i = 0; i < patharray.Count; i++) { dict_path[patharray[i]] = true; } } foreach (var item in self.__instCache) { if (dict_path.ContainsKey(item.Key)) { for (int i = 0; i < item.Value.Count; i++) { var inst = item.Value[i]; if (inst != null) { GameObject.Destroy(inst); self.__goInstCountCache[item.Key]--; } self.__instPathCache.Remove(inst); } } } for (int i = 0; i < patharray.Count; i++) { self.__instCache.Remove(patharray[i]); } if (includePooledGo) { List <string> keys = self.__goPool.Keys.ToList(); for (int i = keys.Count - 1; i >= 0; i--) { var path = keys[i]; if (patharray != null && dict_path.ContainsKey(path) && self.__goPool.TryOnlyGet(path, out var pooledGo)) { if (pooledGo != null && self.__CheckNeedUnload(path)) { ResourcesComponent.Instance.ReleaseAsset(pooledGo); self.__goPool.Remove(path); } } } } }
static void __InitGoChildCount(this GameObjectPoolComponent self, string path, GameObject go) { if (!self.__IsOpenCheck()) { return; } if (!self.__goChildsCountPool.ContainsKey(path)) { Dictionary <string, int> childsCountMap = new Dictionary <string, int>(); int total_child_count = self.RecursiveGetChildCount(go.transform, "", ref childsCountMap); self.__goChildsCountPool[path] = total_child_count; self.__detailGoChildsCount[path] = childsCountMap; } }
static bool __CheckInstIsInPool(this GameObjectPoolComponent self, string path, GameObject inst) { if (self.__instCache.TryGetValue(path, out var inst_array)) { for (int i = 0; i < inst_array.Count; i++) { if (inst_array[i] == inst) { return(true); } } } return(false); }
public static async ETTask <T> GetUIGameObjectAsync <T>(this GameObjectPoolComponent self, string path) where T : Entity, IAwake { var obj = await self.GetGameObjectAsync(path); if (obj == null) { return(null); } T res = self.AddChild <T>(); res.AddUIComponent <UITransform, Transform>("", obj.transform); UIEventSystem.Instance.OnCreate(res); return(res); }
//预加载一系列资源 public static async ETTask LoadDependency(this GameObjectPoolComponent self, List <string> res) { if (res.Count <= 0) { return; } using (ListComponent <ETTask> TaskScheduler = ListComponent <ETTask> .Create()) { for (int i = 0; i < res.Count; i++) { TaskScheduler.Add(self.PreLoadGameObjectAsync(res[i], 1)); } await ETTaskHelper.WaitAll(TaskScheduler); } }
//异步获取:必要时加载 public static async ETTask <GameObject> GetGameObjectAsync(this GameObjectPoolComponent self, string path, Action <GameObject> callback = null) { if (self.TryGetFromCache(path, out var inst)) { self.InitInst(inst); callback?.Invoke(inst); return(inst); } await self.PreLoadGameObjectAsync(path, 1); if (self.TryGetFromCache(path, out inst)) { self.InitInst(inst); callback?.Invoke(inst); return(inst); } callback?.Invoke(null); return(null); }
// 检测是否已经被缓存 static bool CheckHasCached(this GameObjectPoolComponent self, string path) { if (string.IsNullOrEmpty(path)) { Log.Error("path err :\"" + path + "\""); return(false); } if (!path.EndsWith(".prefab")) { Log.Error("GameObject must be prefab : \"" + path + "\""); return(false); } if (self.__instCache.ContainsKey(path) && self.__instCache[path].Count > 0) { return(true); } return(self.__goPool.ContainsKey(path)); }
// 释放资源 public static void __ReleaseAsset(this GameObjectPoolComponent self, string path) { if (self.__instCache.ContainsKey(path)) { for (int i = self.__instCache[path].Count - 1; i >= 0; i--) { self.__instPathCache.Remove(self.__instCache[path][i]); GameObject.Destroy(self.__instCache[path][i]); self.__instCache[path].RemoveAt(i); } self.__instCache.Remove(path); self.__goInstCountCache.Remove(path); } if (self.__goPool.TryOnlyGet(path, out var pooledGo) && self.__CheckNeedUnload(path)) { ResourcesComponent.Instance.ReleaseAsset(pooledGo); self.__goPool.Remove(path); } }
//添加需要持久化的资源 public static void AddPersistentPrefabPath(this GameObjectPoolComponent self, string path) { self.__persistentPathCache[path] = true; }
/// <summary> /// 检查指定路径是否有未回收的预制体 /// </summary> /// <param name="path"></param> private static bool __CheckNeedUnload(this GameObjectPoolComponent self, string path) { return(!self.__instPathCache.ContainsValue(path)); }
static bool __IsOpenCheck(this GameObjectPoolComponent self) { return(Define.Debug); }