private void OnEnable() { markerPoolParent = transform.Find(markerPoolParentName); markerPool = new TransformPool(markerPoolParent); playerWorldPositionPath.Subscribe(State.Instance.Player.WorldPositionPath, HandlePlayerWorldPositionPathChange); }
/// <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); }
private void OnEnable() { markerPoolParent = transform.Find(markerPoolParentName); markerPool = new TransformPool(markerPoolParent); inputWorldPositions.Subscribe(State.Instance.Input.WorldPositions, HandleInputWorldPositionsChange); }
/// <summary> /// 分批预加载实例(细节执行)。 /// </summary> /// <param name="poolName">对象池名称。</param> /// <param name="prefab">Prefab。</param> /// <param name="amount">创建的实例总数量。</param> /// <param name="perAmount">每帧创建的实例数量,为 0 是一次性创建全部。</param> private void DoPreload(string poolName, Transform prefab, int amount, int perAmount) { PrefabPool prefabPool = GetPrefabPool(prefab); TransformPool transformPool = GetTransformPool(poolName); bool prefabEnabled = prefab.gameObject.activeSelf; prefab.gameObject.SetActive(false); perAmount = perAmount <= 0 ? amount : perAmount; StartPreloading(prefabPool, prefabEnabled, transformPool, amount, perAmount); }
/// <summary> /// 创建一个新的物体并挂接一个 PoolEntity 组件。 /// </summary> /// <param name="prefabPool">Prefab 对象池。</param> /// <param name="transformPool">Transform 对象池。</param> /// <param name="enable">是否激活。</param> /// <param name="position">创建后的初始位置。</param> /// <param name="rotation">创建后的初始方向。</param> /// <returns>创建出来的实例。</returns> private static Transform Instantiate(PrefabPool prefabPool, TransformPool transformPool, bool enable, out PoolEntity comp, Vector3 position = default(Vector3), Quaternion rotation = default(Quaternion)) { if (count >= Instance.maxCount) { throw new ApplicationException( "POOL MANAGER: \nThe number of game objects has reached its limit! Try to increase the Max Count of PoolManager."); } // 创建新的实例 Transform xform; xform = Instantiate(prefabPool.Prefab, position, rotation) as Transform; prefabPool.Count += 1; xform.name += prefabPool.Count.ToString("#000"); // 添加 PoolEntity/PoolParticle 组件 ParticleSystem ps = xform.GetComponent <ParticleSystem>(); comp = ps ? xform.gameObject.AddComponent <PoolParticle>() : xform.gameObject.AddComponent <PoolEntity>(); comp.PrefabPool = prefabPool; comp.Prefab = prefabPool.Prefab; comp.Index = count; comp.OriginalScale = xform.localScale; // 添加到大数组 allTransforms[count] = xform; allPoolEntities[count] = comp; count += 1; // 添加到 prefab 对象池 if (enable) { comp.IsDespawned = false; } else { prefabPool.DisabledPool.Push(comp.Index); } // 添加到 Transform 对象池 // need comp.Index AddToTransformPool(xform, comp, transformPool, enable); return(xform); }
/// <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 // lol #if UNITY_EDITOR if (!Application.isPlaying) { //var prefabType = UnityEditor.PrefabUtility.GetPrefabType(gameObject); var prefabType = UnityEditor.PrefabUtility.GetPrefabAssetType(gameObject); var prefabStatus = UnityEditor.PrefabUtility.GetPrefabInstanceStatus(gameObject); //if (prefabType == UnityEditor.PrefabType.None || (int)prefabType >= (int)UnityEditor.PrefabType.PrefabInstance) if (prefabType == UnityEditor.PrefabAssetType.NotAPrefab && prefabStatus == UnityEditor.PrefabInstanceStatus.NotAPrefab || (int)prefabStatus >= (int)UnityEditor.PrefabInstanceStatus.Disconnected) { 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. int id = PoolIdValue(gameObject); TransformPool pool = null; if (Pools.TryGetValue(id, out pool)) { pool.RelenquishObject(gameObject.transform); } else { Destroy(gameObject); } }
/// <summary> /// 创建 Transform 对象池。 /// </summary> /// <param name="name">对象池名称。</param> /// <returns>TransformPool 对象。</returns> private static TransformPool CreateTransformPool(string name) { if (!root) { CreateRoot(); } TransformPool pool = new TransformPool(); pool.PoolName = name; pool.Group = (new GameObject(name)).transform; pool.Group.SetParent(root); transformPoolDic.Add(name, pool); return(pool); }
/// <summary> /// This forces all entities that came from the specified pool to immediately /// relenquish back to it. Note that this may cause some entities /// to become destroyed if the pool is at full capcity. /// </summary> /// <param name="poolId"></param> public static void RelenquishPool(TransformPool pool) { //there are no pooled resources when in edit mode #if UNITY_EDITOR if (!Application.isPlaying) { return; } #endif //if there is no instance, there can't possibly be any pools if (pool != null && Instance != null) { pool.RecallAll(); //BUG ALERT: not setting PoolId.InPool! } }
// ------------------------------------------------------ // Spawn // ------------------------------------------------------ /// <summary> /// 将一个物体加入对象池。 /// </summary> /// <param name="xform">物体实例。</param> /// <param name="comp">物体实例上的 PoolEntity 组件。</param> /// <param name="pool">对象池 Transform。</param> /// <param name="enable">物体是否活跃。</param> private static void AddToTransformPool(Transform xform, PoolEntity comp, TransformPool pool, bool enable) { if (enable) { pool.EnabledPool.Add(comp.Index); } else { pool.DisabledPool.Add(comp.Index); } comp.TransformPool = pool; comp.Group = pool.Group; comp.PoolName = pool.PoolName; xform.SetParent(pool.Group); }
/// <summary> /// 回收一个实例。 /// </summary> /// <param name="index">实例在大数组中的索引。</param> /// <param name="reparent">是否重新挂接到所属的对象池节点。</param> /// <exception cref="ApplicationException">实例早已被回收。</exception> public static void Despawn(int index, bool reparent = true) { PoolEntity comp = allPoolEntities[index]; if (!comp) { #if !UNITY_EDITOR Debug.Log("It seems that the whole object pool has been destroyed."); #endif return; } TransformPool transformPool = transformPoolDic[comp.PoolName]; PrefabPool prefabPool = prefabPoolDic[comp.Prefab]; if (comp.IsDespawned) { throw new ApplicationException(string.Format( "Game object seems to be despawned already: {0}", GetByIndex(index).name)); } prefabPool.DisabledPool.Push(index); transformPool.EnabledPool.Remove(index); transformPool.DisabledPool.Add(index); // 1. 调用所有 PoolBehaviour 组件的 OnDespawn() 方法 // 2. 特定类型的 PoolEntity 有时候需要在 Despawn 时执行一些特定的工作,如 PoolParticle 清除粒子等 comp.OnDespawn(); comp.gameObject.SetActive(false); if (reparent) { allTransforms[index].SetParent(comp.Group); } if (comp.OnDespawnedCallback != null) { comp.OnDespawnedCallback(); comp.OnDespawnedCallback = null; } comp.IsDespawned = true; }
/// <summary> /// 分批加载实例协程。 /// </summary> /// <param name="prefabPool">Prefab 对象池。</param> /// <param name="prefabEnabled">Prefab 对象池活跃实例集合。</param> /// <param name="transformPool">Transform 对象池。</param> /// <param name="amount">创建的实例总数量。</param> /// <param name="perAmount">每帧创建的实例数量,为 0 时一次性创建全部。</param> /// <returns>IEnumerator 对象。</returns> internal IEnumerator PreloadBatch(PrefabPool prefabPool, bool prefabEnabled, TransformPool transformPool, int amount, int perAmount) { yield return(new WaitForEndOfFrame()); PoolEntity comp; for (int i = 0; i < perAmount; i++) { Instantiate(prefabPool, transformPool, false, out comp); amount -= 1; if (amount == 0) { prefabPool.Prefab.gameObject.SetActive(prefabEnabled); yield break; } } StartCoroutine(PreloadBatch(prefabPool, prefabEnabled, transformPool, amount, perAmount)); }
/// <summary> /// 开始执行分批加载实例。 /// </summary> /// <param name="prefabPool">Prefab 对象池。</param> /// <param name="prefabEnabled">Prefab 对象池活跃实例集合。</param> /// <param name="transformPool">Transform 对象池。</param> /// <param name="amount">创建的实例总数量。</param> /// <param name="perAmount">每帧创建的实例数量,为 0 时一次性创建全部。</param> internal void StartPreloading(PrefabPool prefabPool, bool prefabEnabled, TransformPool transformPool, int amount, int perAmount) { StartCoroutine(PreloadBatch(prefabPool, prefabEnabled, transformPool, amount, perAmount)); }