/// <summary> /// Returns a pool that is appropriate for storing identical copies of an object. /// </summary> static TransformPool GetAssociatedPool(GameObject gameObject, int chunkSize, int maxPoolSize) { //first, we need to know the id we will be using for this object's pool //if there is no PoolId attached we know this wasn't created by this pooler. //In that case, treat is as a prefab. WARNING: If it isn't actually a prefab and we //destroy it later, this could cause some serious issues! PoolId p = null; int id = PoolIdValue(gameObject, out p); //now we need to see if we have a pool for it yet TransformPool pool = null; if (!Pools.TryGetValue(id, out pool)) { //looks like we need to create a new pool for this type of object GameObject go = new GameObject("Pool: " + id + " (" + gameObject.name + ")"); go.transform.SetParent(Instance.transform, false); pool = go.AddComponent <TransformPool>(); pool.PoolId = id; Pools[id] = pool; pool.ChunkSize = chunkSize; pool.MaxPoolSize = maxPoolSize; pool.AllocTime = AllocTime; //WARNING: This is a potential bug if we actually passed a live object and not a prefab! //If we destroy the live object, we can't properly use the pool associated with it! pool.Prefab = gameObject.transform; } return(pool); }
/// <summary> /// Returns the object to this pool. If the pool is at /// capcity, the object will be destroyed instead. /// Objects relenquished this way should be considered /// destroyed for all intents and purposes and must never /// be accessed again without using the pool's 'obtain' method. /// </summary> /// <param name="thing"></param> public virtual void RelenquishObject(T thing, PoolId poolId = null) { _ActiveList.Remove(thing.gameObject); #if UNITY_EDITOR if (!Application.isPlaying) { //TODO: check if slot or this pool is a prefab before destroying //NOTE: There is no built-in surefire way to determine prefab status //but rumor has it that the hideflags can be used to imply such a status GameObject.DestroyImmediate(thing.gameObject); return; } #endif #if UNITY_EDITOR if (TypeHelper.IsReferenceNull(transform) || transform.childCount >= MaxPoolSize) #else if (transform.childCount >= MaxPoolSize) #endif { //if we have enough in our pool, just destroy #if UNITY_EDITOR if (Application.isPlaying) { GameObject.Destroy(thing.gameObject); } else { GameObject.DestroyImmediate(thing.gameObject); } #else GameObject.Destroy(thing.gameObject); #endif } else { //send back to pool thing.gameObject.SetActive(false); //TODO: Confirm if this is still a bug in 5.6+ //thing.transform.SetParent(null); //must do this due to bug in Unity involving prefabs thing.transform.SetParent(this.transform); //NOTE: not an entirely pure system anymore... but whatever if (poolId != null) { poolId.InPool = true; } else { poolId = thing.GetComponent <PoolId>(); if (poolId != null) { poolId.InPool = true; } } } }
/// <summary> /// Helper for retreiving the number used to identify /// to what pool an object should belong. /// </summary> /// <param name="gameObject"></param> /// <returns></returns> public static int PoolIdValue(GameObject gameObject, out PoolId pool) { int id; var poolId = gameObject.GetComponent <PoolId>(); if (poolId != null) { id = poolId.Id; } else { id = gameObject.GetInstanceID(); } pool = poolId; return(id); }
/// <summary> /// Relenquishes an object to the internal pooling mechanism. For all intents /// and purposes, this should be treated the same as calling Destroy on the GameObject /// and it should no longer be accessed. If the internal pool is at maximum capacity /// the GameObject will be destroyed. /// /// Note that even if an object was not instantiated using a pool, it can still be /// relenquished to one, however, the pool it is placed in will not be the same one /// as any other copies that were instantiated using Summon(). /// </summary> /// <param name="gameObject"></param> public static void RelenquishToPool(GameObject gameObject) { if (gameObject == null) { return; } //don't use pools during editmode, it f***s everything #if UNITY_EDITOR if (!Application.isPlaying) { var prefabType = UnityEditor.PrefabUtility.GetPrefabType(gameObject); if (prefabType == UnityEditor.PrefabType.None || (int)prefabType >= (int)UnityEditor.PrefabType.PrefabInstance) { DestroyImmediate(gameObject); } else { Debug.LogWarning("Could not destroy prefab: " + gameObject.name); } return; } #endif if (MaxPoolSize < 1) { Destroy(gameObject); return; } //If we don't have a pool for this object's id //we know it didn't come from one. We just want //to destroy it like normal. PoolId p = null; int id = PoolIdValue(gameObject, out p); TransformPool pool = null; if (Pools.TryGetValue(id, out pool)) { pool.RelenquishObject(gameObject.transform, p); } else { Destroy(gameObject); } }