using UnityEngine; using System.Collections.Generic; namespace FORGE3D { public class F3DPool : MonoBehaviour { [HideInInspector] public string poolName = "GeneratedPool"; // name of pool [HideInInspector] public Transform[] templates = new Transform[0]; // templates [HideInInspector] public Transform[] templatesParent = new Transform[0]; // parents of each type of template [HideInInspector] public int[] poolLength = new int[0]; // base items count [HideInInspector] public int[] poolLengthCurrent = new int[0]; // Effect pool items current count [HideInInspector] public int[] poolLengthMax = new int[0]; // max items count [HideInInspector] public string broadcastSpawnName = "OnSpawned"; // name of onSpawned function [HideInInspector] public string broadcastDespawnName = "OnDespawned"; // name of ondespawned function [HideInInspector] public bool delayedSpawnInInstall = true; // If we need to install all not in 1 update [HideInInspector] public int objectsPerUpdate = -1; // Current count of installing objects per frame [HideInInspector] public bool needBroadcasting = true; // if we need broadcasting |=> True [HideInInspector] public bool optimizeSpawn = true; // This is option for automated objectsPerUpdate calculation [HideInInspector] public int targetFPS = 50; // Target FPS for optimizeSpawn [HideInInspector] public bool pooling = true; // If need pooling? [HideInInspector] public bool needDebugging = false; // If need debugging [HideInInspector] public bool needSort = true; // if Need sort? It means, that after Despawn() it will be parented to it's template's parent [HideInInspector] public bool needParenting = true; // if need start parenting to parents private float normalValue = 0f; // Calculation of optimizeSpawn(not for editing) private Dictionary> readyObjects = new Dictionary>(); // Dict of ready for spawn items private Dictionary> occupiedObjects = new Dictionary>(); // Dict of ready for despawn items private bool installing = true; // if pool still installling = it will be true //return count of temlates public int GetTemplatesCount() { if (templates != null) { return templates.Length; } return -1; } //returns is template in this pool bool CheckForExistingTemplate(Transform obj) { int i; for (i = 0; i < templates.Length; i++) { if (obj == templates[i]) { return true; } } return false; } // Despawn - called for despawning some object, that was spawned public bool Despawn(Transform obj) { bool res = false; int i = 0, n = 0, j = 0; for (j = 0; j < occupiedObjects.Count; j++) { List transforms = occupiedObjects[templates[j]]; int transformsCount = transforms.Count; for (i = 0; i < transformsCount; i++) { if (transforms[i] == obj) { res = true; transforms.RemoveAt(i); readyObjects[templates[j]].Add(obj); obj.gameObject.SetActive(false); if (needSort) { if (needParenting) { obj.parent = templatesParent[n]; } } if (needBroadcasting && broadcastDespawnName != "") obj.BroadcastMessage(broadcastDespawnName, SendMessageOptions.DontRequireReceiver); break; } } n++; } return res; } // If you have parent(template) of spawned object - use this variant for better perfomance! public bool Despawn(Transform obj, Transform template) { bool res = false; int i, j; for (i = 0; i < templates.Length; i++) { if (templates[i] == template) { int listSize = occupiedObjects[template].Count; for (j = 0; j < listSize; j++) { if (occupiedObjects[template][j] == obj) { res = true; occupiedObjects[template].RemoveAt(j); obj.gameObject.SetActive(false); if (needSort) obj.parent = templatesParent[i]; readyObjects[template].Add(obj); break; } } if (res) { break; } } } return res; } //Return template position in array public int GetTemplatePosition(Transform obj) { int pos = -1; int i; for (i = 0; i < templates.Length; i++) { if (obj == templates[i]) { pos = i; } } return pos; } /// /// This function spawns audiosource somewhere with it's clip /// /// Source template /// Clip that have to be played /// Place to spawn audio /// Parent of spawned audiosource /// Link to spawned audio source public Transform SpawnAudio(Transform obj, AudioClip clip, Vector3 pos, Transform par) { Transform tempTransform; int i; int curPos = GetTemplatePosition(obj); for (i = 0; i < readyObjects[templates[curPos]].Count; i++) { if (!readyObjects[templates[curPos]][i].gameObject.activeSelf) { tempTransform = readyObjects[templates[curPos]][i]; readyObjects[templates[curPos]].RemoveAt(i); occupiedObjects[templates[curPos]].Add(tempTransform); tempTransform.position = pos; if (par == null) { tempTransform.SetParent(null); } else { tempTransform.SetParent(par); } tempTransform.gameObject.SetActive(true); if (needBroadcasting && broadcastSpawnName != "") tempTransform.BroadcastMessage(broadcastSpawnName, SendMessageOptions.DontRequireReceiver); AudioSource source = tempTransform.gameObject.GetComponent(); if (source != null) { source.clip = clip; } return tempTransform; } } if (poolLengthCurrent[curPos] < poolLengthMax[curPos]) { poolLengthCurrent[curPos]++; Transform newGO = Instantiate(templates[curPos], Vector3.zero, Quaternion.identity) as Transform; newGO.transform.parent = this.gameObject.transform; newGO.gameObject.SetActive(true); newGO.position = pos; if (par == null) { newGO.SetParent(null); } else { newGO.SetParent(par); } occupiedObjects[templates[curPos]].Add(newGO); if (needBroadcasting && broadcastSpawnName != "") newGO.BroadcastMessage(broadcastSpawnName, SendMessageOptions.DontRequireReceiver); AudioSource source = newGO.gameObject.GetComponent(); if (source != null) { source.clip = clip; } return newGO; } return null; } //Return transfrom of spawned object public Transform Spawn(Transform obj, Transform par, Vector3 pos = new Vector3(), Quaternion rot = new Quaternion()) { if (!CheckForExistingTemplate(obj)) { if (needDebugging) Debug.LogWarning(obj.name + " isn't in " + this.gameObject.name + "'s pool"); return null; } Transform tempTransform; int i; int curPos = GetTemplatePosition(obj); for (i = 0; i < readyObjects[obj].Count; i++) { if (!readyObjects[obj][i].gameObject.activeSelf) { tempTransform = readyObjects[obj][i]; readyObjects[obj].RemoveAt(i); occupiedObjects[obj].Add(tempTransform); tempTransform.position = pos; tempTransform.rotation = rot; if (par == null) { tempTransform.SetParent(null); } else { tempTransform.SetParent(par); } tempTransform.gameObject.SetActive(true); if (needBroadcasting && broadcastSpawnName != "") tempTransform.BroadcastMessage(broadcastSpawnName, SendMessageOptions.DontRequireReceiver); return tempTransform; } } if (poolLengthCurrent[curPos] < poolLengthMax[curPos]) { poolLengthCurrent[curPos]++; Transform newGO = Instantiate(templates[curPos], Vector3.zero, Quaternion.identity) as Transform; newGO.transform.parent = this.gameObject.transform; newGO.gameObject.SetActive(true); newGO.position = pos; newGO.rotation = rot; if (par == null) { newGO.SetParent(null); } else { newGO.SetParent(par); } occupiedObjects[obj].Add(newGO); if (needBroadcasting && broadcastSpawnName != "") newGO.BroadcastMessage(broadcastSpawnName, SendMessageOptions.DontRequireReceiver); return newGO; } return null; } //Return transfrom of spawned object public Transform Spawn(Transform obj, Vector3 pos , Quaternion rot , Transform par) { if (!CheckForExistingTemplate(obj)) { if (needDebugging) Debug.LogWarning(obj.name + " isn't in " + this.gameObject.name + "'s pool"); return null; } Transform tempTransform; int i; int curPos = GetTemplatePosition(obj); for (i = 0; i < readyObjects[obj].Count; i++) { if (!readyObjects[obj][i].gameObject.activeSelf) { tempTransform = readyObjects[obj][i]; readyObjects[obj].RemoveAt(i); occupiedObjects[obj].Add(tempTransform); tempTransform.position = pos; tempTransform.rotation = rot; if (par == null) { tempTransform.SetParent(null); } else { tempTransform.SetParent(par); } tempTransform.gameObject.SetActive(true); if (needBroadcasting && broadcastSpawnName != "") tempTransform.BroadcastMessage(broadcastSpawnName, SendMessageOptions.DontRequireReceiver); return tempTransform; } } if (poolLengthCurrent[curPos] < poolLengthMax[curPos]) { poolLengthCurrent[curPos]++; Transform newGO = Instantiate(templates[curPos], Vector3.zero, Quaternion.identity) as Transform; newGO.transform.parent = this.gameObject.transform; newGO.gameObject.SetActive(true); newGO.position = pos; newGO.rotation = rot; if (par == null) { newGO.SetParent(null); } else { newGO.SetParent(par); } occupiedObjects[obj].Add(newGO); if (needBroadcasting && broadcastSpawnName != "") newGO.BroadcastMessage(broadcastSpawnName, SendMessageOptions.DontRequireReceiver); return newGO; } return null; } //Return transfrom of spawned object public Transform Spawn(Transform obj, Vector3 pos = new Vector3(), Quaternion rot = new Quaternion()) { if (!CheckForExistingTemplate(obj)) { if (needDebugging) Debug.LogWarning(obj.name + " isn't in " + this.gameObject.name + "'s pool"); return null; } Transform tempTransform; int i; int curPos = GetTemplatePosition(obj); for (i = 0; i < readyObjects[obj].Count; i++) { if (!readyObjects[obj][i].gameObject.activeSelf) { tempTransform = readyObjects[obj][i]; readyObjects[obj].RemoveAt(i); occupiedObjects[obj].Add(tempTransform); tempTransform.position = pos; tempTransform.rotation = rot; tempTransform.SetParent(null); tempTransform.gameObject.SetActive(true); if (needBroadcasting && broadcastSpawnName != "") tempTransform.BroadcastMessage(broadcastSpawnName, SendMessageOptions.DontRequireReceiver); return tempTransform; } } if (poolLengthCurrent[curPos] < poolLengthMax[curPos]) { poolLengthCurrent[curPos]++; Transform newGO = Instantiate(templates[curPos], Vector3.zero, Quaternion.identity) as Transform; newGO.transform.parent = this.gameObject.transform; newGO.gameObject.SetActive(true); newGO.position = pos; newGO.rotation = rot; newGO.SetParent(null); occupiedObjects[obj].Add(newGO); if (needBroadcasting && broadcastSpawnName != "") newGO.BroadcastMessage(broadcastSpawnName, SendMessageOptions.DontRequireReceiver); return newGO; } return null; } //Updating templates array public void SetTemplates(Transform[] newArray) { templates = newArray; } //updating poolLength array public void SetLength(int[] newPoolLenght) { poolLength = newPoolLenght; } //updating poolLengthMax public void SetLengthMax(int[] newPoolLengthMax) { poolLengthMax = newPoolLengthMax; } //Automatic spawning function void CalculateObjectsPerUpdate() { if (objectsPerUpdate != 0) { if (objectsPerUpdate == -1) { objectsPerUpdate = 1; } else { objectsPerUpdate = (int)(objectsPerUpdate * (normalValue / Time.deltaTime)); if (objectsPerUpdate == 0) { objectsPerUpdate = 1; } } } } //Delayed spawn function. Instantiates objects not in one frame. void DelayedSpawnInInstall() { if (optimizeSpawn) { CalculateObjectsPerUpdate(); } int leftObjectsToInstall = objectsPerUpdate; int i, j; for (i = 0; i < templates.Length; i++) { for (j = 0; j < poolLength[i]; j++) { if (poolLengthCurrent[i] < poolLength[i]) { InstantiateItem(templates[i], templatesParent[i], i); leftObjectsToInstall--; if (leftObjectsToInstall == 0) { break; } } } if (leftObjectsToInstall == 0) { break; } } if (leftObjectsToInstall != 0) { installing = false; } } //Instantiates all objects void NonDelayedSpawnInInstall() { for (int i = 0; i < templates.Length; i++) { for (int j = 0; j < poolLength[i]; j++) { if (poolLengthCurrent[i] < poolLength[i]) { InstantiateItem(templates[i], templatesParent[i], i); } } } } void Update() { if (installing) { if (pooling == false) { installing = false; } else { //Delayed spawn in install if (delayedSpawnInInstall) { DelayedSpawnInInstall(); } else { NonDelayedSpawnInInstall(); installing = false; } } } } // Instantiating item Transform InstantiateItem(Transform temp, Transform par, int templatePosition) { Transform newGO = Instantiate(temp, Vector3.zero, Quaternion.identity) as Transform; newGO.transform.SetParent(par); newGO.gameObject.SetActive(false); readyObjects[temp].Add(newGO); poolLengthCurrent[templatePosition]++; return newGO; } //Installing basic arrays for working with this pool public void Install() { poolLengthCurrent = new int[poolLength.Length]; templatesParent = new Transform[templates.Length]; int i; for (i = 0; i < templates.Length; i++) { if (templates[i] != null) { if (needParenting) { GameObject newParent = new GameObject(templates[i].name); templatesParent[i] = newParent.transform; newParent.transform.SetParent(this.transform); List tempList = new List(); if (tempList != null) { readyObjects.Add(templates[i], tempList); } occupiedObjects.Add(templates[i], new List()); } else { List tempList = new List(); if (tempList != null) { readyObjects.Add(templates[i], tempList); } occupiedObjects.Add(templates[i], new List()); } } } if (targetFPS == 0) { targetFPS = 60; } normalValue = 1f / targetFPS; installing = true; } } }