(Question at the bottom of the thread) I'm currently instantiating and destroying my game objects. I was told to use object pooling so that's what I want to achieve now. Unfortunately I'm having alot of issues implementing this object pooling in my own game . I've watched the tutorial from Sebastian Lague and copied him and here is what I currently have: The PoolManager (attached to a random gameObject): Code (CSharp): using System.Collections; using System.Collections.Generic; using UnityEngine; public class PoolManager : MonoBehaviour { //Int = key Dictionary<int, Queue<GameObject>> poolDictionary = new Dictionary<int, Queue<GameObject>> (); //Singleton pattern to get acces to these methods without reference to the PoolManager static PoolManager _instance; public static PoolManager instance { get { if (_instance == null) { _instance = FindObjectOfType<PoolManager>(); } return _instance; } } //Create the pool defined by a gameObject and a size public void CreatePool(GameObject prefab, int poolSize) { //Key is unique for each prefab int poolKey = prefab.GetInstanceID(); //Make sure the poolkey is already in our dictionary because it will cause errors if we don't if (!poolDictionary.ContainsKey(poolKey)) { poolDictionary.Add(poolKey, new Queue<GameObject>()); } //Instantiate prefabs to create te pool for (int i = 0; i < poolSize; i++) { GameObject newObject = Instantiate(prefab) as GameObject; newObject.SetActive(false); //Add to the pool poolDictionary[poolKey].Enqueue(newObject); } } public void ReuseObject(GameObject prefab, Vector3 position, Quaternion rotation) { int poolKey = prefab.GetInstanceID(); //Make sure that the pool contains the key if (poolDictionary.ContainsKey(poolKey)) { //Get first object of the queue GameObject objectToReuse = poolDictionary[poolKey].Dequeue(); //Add object back to the end of the queue so we can reuse it again later poolDictionary[poolKey].Enqueue(objectToReuse); objectToReuse.SetActive(true); objectToReuse.transform.position = position; objectToReuse.transform.rotation = rotation; } } } The TestManager (Also attached to a random gameObject. Here I'm defining the prefab and the size of the pool. Also I'm saying here that I want to spawn a "new" prefab every second.): Code (CSharp): using System.Collections; using System.Collections.Generic; using UnityEngine; public class TestManager : MonoBehaviour { public GameObject prefab; public float delayTimer = 1.0f; float timer; // Use this for initialization void Start () { PoolManager.instance.CreatePool(prefab, 5); timer = delayTimer; } // Update is called once per frame void Update () { timer -= Time.deltaTime; if (timer <= 0) { Vector3 poolVector = new Vector3(0, 8, 0); PoolManager.instance.ReuseObject(prefab, poolVector, Quaternion.identity); timer = delayTimer; } } } The TestObject (Attached to the prefab --> movement): Code (CSharp): using System.Collections; using System.Collections.Generic; using UnityEngine; public class TestObject : MonoBehaviour { private void Update() { transform.Translate(-Vector3.up * Time.deltaTime * 10); } } QUESTION: Sebastian is using everytime the same prefab (a cube), so just ONE object. I have around 70 different prefabs which I want to spawn in a random order. I've tried several things with an array but I just can't get it to work that's why I'm asking you guys.
The best result I had was by editing the TestManager script. I managed to create a pool with all the different objects but only one object was active and actually moving in play mode. Here is the script: Code (CSharp): using System.Collections; using System.Collections.Generic; using UnityEngine; public class TestManager : MonoBehaviour { public GameObject[] prefabArray; GameObject prefab; public float delayTimer = 1.0f; float timer; // Use this for initialization void Start () { foreach (GameObject go in prefabArray) { prefab = go; PoolManager.instance.CreatePool(prefab, 1); } timer = delayTimer; } // Update is called once per frame void Update () { timer -= Time.deltaTime; if (timer <= 0) { Vector3 poolVector = new Vector3(0, 8, 0); PoolManager.instance.ReuseObject(prefab, poolVector, Quaternion.identity); timer = delayTimer; } } }
So what exactly are you wanting from the pooler? Are you wanting: 70 (completely) different objects each stored only once within the pool. One object stored 70 times within the pool. Some other combination?
The first thing. I want to get 70 completely different objects in the pool and reuse them in a random order. Currently I can only store one prefab/object and that's the issue :/
You could create List<GameObject> m_objects;, populate it and then just use Random.Range(0, m_objects.Count) to get one at random and remove it from the list.
Hello thanks for the input this is what I made of it (only changed the testManager script). Also needed to add another list because I didn't want to reuse a object while it's still visible in the canvas. Can you overlook this? I'm pretty new to programming and I would love to know if I'm making huge mistakes. Like in this code everything is in the update are there any ways to avoid this or should I use coroutines or something? Should I avoid the while loop? PS: I've tested the code several times and it works perfect Code (CSharp): using System.Collections; using System.Collections.Generic; using UnityEngine; public class TestManager : MonoBehaviour { public List<GameObject> m_objects; public List<int> used_numbers; int carNo; float carTimer; public float carDelayTimer = 1.0f; // Use this for initialization void Start () { carTimer = carDelayTimer; //Create pool with all the objects in the list foreach (GameObject go in m_objects) { PoolManager.instance.CreatePool(go, 1); } } // Update is called once per frame void Update () { carTimer -= Time.deltaTime; if (carTimer <= 0) { //Spawnposition Vector3 poolVector = new Vector3(0, 8, 0); carNo = Random.Range(0, m_objects.Count); //As long as the generated carNo already exists in the used_numbers list we generate a new carNo //In this way we can make sure that we don't reuse a object while it's still visible in the canvas while (used_numbers.Contains(carNo)) { carNo = Random.Range(0, m_objects.Count); } used_numbers.Add(carNo); PoolManager.instance.ReuseObject(m_objects[carNo], poolVector, Quaternion.identity); carTimer = carDelayTimer; } //We want to clear the list regularly for two reasons //1. if we don't do this and our gameObjects are all used the while loop in the update makes the game crash //2. we want to reuse the cars if (used_numbers.Count >= 10) { used_numbers.RemoveRange(0, used_numbers.Count - 5); } } }
Sure, that's a pretty decent stab at it. If I had to pick a single main point to focus on there, it would be with the separation of responsibilities. That is to say, let the pool manager look after the handling of the 'available' and 'used' caches. Hide that stuff away from the outside world. So maybe it could look something like this (note: this is untested and deliberately incomplete) :- Code (CSharp): public class PoolManager : MonoBehaviour { public void Add(GameObject addToPool) { m_poolAvailable.Add(addToPool); } // Be sure to test the return value here. On exhaustion, it will return null. public GameObject GetRandom() { if (m_poolAvailable.Count == 0) return null; var randIndex = Random.Range(0, m_poolAvailable.Count); var available = m_poolAvailable[randIndex]; // TO DO : move 'available' object from the 'available' to the 'in use' pool. return available; } public void ReturnToPool(GameObject returnToPool) { // TO DO : is 'returnToPool' in the 'in use' pool? if (is_in_use) { // TO DO : move 'returnToPool' object from the 'in use' to the 'available' pool. } } List<GameObject> m_poolAvailable = new List<GameObject>(); List<GameObject> m_poolInUse = new List<GameObject>(); }
if someone wants to help something, you should either really help or don't start answering at all and say it's not complete on purpose
And you're pointlessly necroing a thread from 2018. You're not bringing anything helpful to the thread either. Unity has a tutorial for object pooling in their learn section https://learn.unity.com/tutorial/introduction-to-object-pooling
Now and after so many learn about the pooling, I can manage without such half helps. but I think that here is a Community and who you want to help, you should do right and not half-right. A question? why did you come to this thread now?
Please don't necro threads like this, it's against the forum rules. All you're doing here is arguing and not adding anything to the thread. Adding some useful content to a discussion would be acceptable if the thread wasn't too old but you're not doing that. Please refrain from this. Thanks.
Honest question, why aren't old threads locked? I see this a lot on this forum, clearly some people aren't aware of the rule and the simple fact that you are able to reply to old threads sort of implies that it's ok to do so.