using UnityEngine; using System.Collections; using System.Collections.Generic; // Cartoon FX - (c) 2012-2016 Jean Moreno // Spawn System: // Preload GameObject to reuse them later, avoiding to Instantiate them. // Very useful for mobile platforms. public class CFX_SpawnSystem : MonoBehaviour { /// <summary> /// Get the next available preloaded Object. /// </summary> /// <returns> /// The next available preloaded Object. /// </returns> /// <param name='sourceObj'> /// The source Object from which to get a preloaded copy. /// </param> /// <param name='activateObject'> /// Activates the object before returning it. /// </param> static public GameObject GetNextObject(GameObject sourceObj, bool activateObject = true) { int uniqueId = sourceObj.GetInstanceID(); if(!instance.poolCursors.ContainsKey(uniqueId)) { Debug.LogError("[CFX_SpawnSystem.GetNextObject()] Object hasn't been preloaded: " + sourceObj.name + " (ID:" + uniqueId + ")\n", instance); return null; } int cursor = instance.poolCursors[uniqueId]; GameObject returnObj = null; if(instance.onlyGetInactiveObjects) { int loop = cursor; while(true) { returnObj = instance.instantiatedObjects[uniqueId][cursor]; instance.increasePoolCursor(uniqueId); cursor = instance.poolCursors[uniqueId]; if(returnObj != null && !returnObj.activeSelf) break; //complete loop: no active instance available if(cursor == loop) { if(instance.instantiateIfNeeded) { Debug.Log("[CFX_SpawnSystem.GetNextObject()] A new instance has been created for \"" + sourceObj.name + "\" because no active instance were found in the pool.\n", instance); PreloadObject(sourceObj); var list = instance.instantiatedObjects[uniqueId]; returnObj = list[list.Count-1]; break; } else { Debug.LogWarning("[CFX_SpawnSystem.GetNextObject()] There are no active instances available in the pool for \"" + sourceObj.name +"\"\nYou may need to increase the preloaded object count for this prefab?", instance); return null; } } } } else { returnObj = instance.instantiatedObjects[uniqueId][cursor]; instance.increasePoolCursor(uniqueId); } if(activateObject && returnObj != null) returnObj.SetActive(true); return returnObj; } /// <summary> /// Preloads an object a number of times in the pool. /// </summary> /// <param name='sourceObj'> /// The source Object. /// </param> /// <param name='poolSize'> /// The number of times it will be instantiated in the pool (i.e. the max number of same object that would appear simultaneously in your Scene). /// </param> static public void PreloadObject(GameObject sourceObj, int poolSize = 1) { instance.addObjectToPool(sourceObj, poolSize); } /// <summary> /// Unloads all the preloaded objects from a source Object. /// </summary> /// <param name='sourceObj'> /// Source object. /// </param> static public void UnloadObjects(GameObject sourceObj) { instance.removeObjectsFromPool(sourceObj); } /// <summary> /// Gets a value indicating whether all objects defined in the Editor are loaded or not. /// </summary> /// <value> /// <c>true</c> if all objects are loaded; otherwise, <c>false</c>. /// </value> static public bool AllObjectsLoaded { get { return instance.allObjectsLoaded; } } // INTERNAL SYSTEM ---------------------------------------------------------------------------------------------------------------------------------------- static private CFX_SpawnSystem instance; public GameObject[] objectsToPreload = new GameObject[0]; public int[] objectsToPreloadTimes = new int[0]; public bool hideObjectsInHierarchy = false; public bool spawnAsChildren = true; public bool onlyGetInactiveObjects = false; public bool instantiateIfNeeded = false; private bool allObjectsLoaded; private Dictionary<int,List<GameObject>> instantiatedObjects = new Dictionary<int, List<GameObject>>(); private Dictionary<int,int> poolCursors = new Dictionary<int, int>(); private void addObjectToPool(GameObject sourceObject, int number) { int uniqueId = sourceObject.GetInstanceID(); //Add new entry if it doesn't exist if(!instantiatedObjects.ContainsKey(uniqueId)) { instantiatedObjects.Add(uniqueId, new List<GameObject>()); poolCursors.Add(uniqueId, 0); } //Add the new objects GameObject newObj; for(int i = 0; i < number; i++) { newObj = (GameObject)Instantiate(sourceObject); newObj.SetActive(false); //Set flag to not destruct object CFX_AutoDestructShuriken[] autoDestruct = newObj.GetComponentsInChildren<CFX_AutoDestructShuriken>(true); foreach(CFX_AutoDestructShuriken ad in autoDestruct) { ad.OnlyDeactivate = true; } //Set flag to not destruct light CFX_LightIntensityFade[] lightIntensity = newObj.GetComponentsInChildren<CFX_LightIntensityFade>(true); foreach(CFX_LightIntensityFade li in lightIntensity) { li.autodestruct = false; } instantiatedObjects[uniqueId].Add(newObj); if(hideObjectsInHierarchy) newObj.hideFlags = HideFlags.HideInHierarchy; if(spawnAsChildren) newObj.transform.parent = this.transform; } } private void removeObjectsFromPool(GameObject sourceObject) { int uniqueId = sourceObject.GetInstanceID(); if(!instantiatedObjects.ContainsKey(uniqueId)) { Debug.LogWarning("[CFX_SpawnSystem.removeObjectsFromPool()] There aren't any preloaded object for: " + sourceObject.name + " (ID:" + uniqueId + ")\n", this.gameObject); return; } //Destroy all objects for(int i = instantiatedObjects[uniqueId].Count - 1; i >= 0; i--) { GameObject obj = instantiatedObjects[uniqueId][i]; instantiatedObjects[uniqueId].RemoveAt(i); GameObject.Destroy(obj); } //Remove pool entry instantiatedObjects.Remove(uniqueId); poolCursors.Remove(uniqueId); } private void increasePoolCursor(int uniqueId) { instance.poolCursors[uniqueId]++; if(instance.poolCursors[uniqueId] >= instance.instantiatedObjects[uniqueId].Count) { instance.poolCursors[uniqueId] = 0; } } //-------------------------------- void Awake() { if(instance != null) Debug.LogWarning("CFX_SpawnSystem: There should only be one instance of CFX_SpawnSystem per Scene!\n", this.gameObject); instance = this; } void Start() { allObjectsLoaded = false; for(int i = 0; i < objectsToPreload.Length; i++) { PreloadObject(objectsToPreload[i], objectsToPreloadTimes[i]); } allObjectsLoaded = true; } }