Hi! Im new to all of this and probably it will be a stupid question. I creates a scipt for object pooling (Unity tutorial http://unity3d.com/learn/tutorials/modules/beginner/live-training-archive/object-pooling). It is working great but it is only for one object so if I want to pool 3 different objects I need to make 3 scripts. I would really like to have all objects in one script. I tried to figure it out reading other posts here on forum but I just can’t make it work… Like I said… I’m a noob =/
I just need help with the last part marker in #region FROM HERE ON I NEED HELP
Any help is appreciated! Thanks!
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
[AddComponentMenu("Gameplay/Objects_Pool")]
public class Objects_Pool : MonoBehaviour
{
public static Objects_Pool objectsPool {get; private set;}
[System.Serializable]
public class Objects_Pool_Entry
{
public GameObject pooledObject;
public int pooledAmount;
public bool expandPoolAmount;
}
public Objects_Pool_Entry[] entries;
List<GameObject>[] pooledObjects;
void Awake ()
{
objectsPool = this;
}
void Start ()
{
pooledObjects = new List<GameObject>[entries.Length];
for (int i = 0; i < entries.Length; i++)
{
var objectpooledObject = entries[i];
pooledObjects[i] = new List<GameObject>();
for (int n = 0; n < objectpooledObject.pooledAmount; n++)
{
var gameObject = Instantiate(objectpooledObject.pooledObject) as GameObject;
gameObject.name = objectpooledObject.pooledObject.name;
PoolObject(gameObject);
}
}
}
public void PoolObject (GameObject newGameObject)
{
for (int i = 0; i < entries.Length; i++)
{
if (entries[i].pooledObject.name != newGameObject.name)
continue;
newGameObject.SetActive(false);
pooledObjects[i].Add(newGameObject);
}
}
#region FROM HERE ON I NEED HELP
// This is the code from original script.
// I would like to change it for my new script that can accept more than one object.
public GameObject GetPooledObjects()
{
for(int i = 0; i < pooledObjects.Count; i++)
{
if(!pooledObjects[i].activeInHierarchy)
{
return pooledObjects[i];
}
}
if(expandPoolAmount)
{
GameObject gameObject = (GameObject)Instantiate(pooledObject);
gameObject.name = pooledObject.name;
pooledObjects.Add (gameObject);
return gameObject;
}
return null;
}
}
#endregion
You can then create 3 game objects with the pooling script and assign the wanted value (prefab, count, etc.)
Or
You could create a script that will create the 3 game objects for you and assign them the pooling script.
But most of all, your initial code can be much simplified, I would do something like this…
Optimized solution
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class MultipleObjectsPooling : MonoBehaviour
{
[System.Serializable]
public class Objects_Pool_Entry
{
public GameObject pooledObject;
public int pooledAmount;
public bool expandPoolAmount;
}
public Objects_Pool_Entry[] pooledEntries;
public List<GameObject> pooledObject;
void Start ()
{
foreach(Objects_Pool_Entry entry in pooledEntries)
{
for(int i = 0; i < entry.pooledAmount; i++)
{
var go = Instantiate(entry.pooledObject) as GameObject;
go.name = entry.pooledObject.name;
pooledObject.Add(go);
go.SetActive(false);
}
}
}
public GameObject GetPooledObjects()
{
foreach(GameObject go in pooledObject)
{
if(!go.activeInHierarchy)
return go;
}
return null;
}
}[CODE][/SPOILER]
Really appreciate that you are trying to help me!!!
Maybe I didn’t explain it well… What I’m trying to achieve is: I will have 3 spaceships each shooting different type of bullets (lets say lazer, plasma, rockets). I’m trying to make my script so I can store all different type of bullets in one pool and with each spaceship only call one type of bullets.
I figured out I need GetObjectForType and I almost did everything… Right now my script at start creates pool of bullets (lets say 10 of each). Spaceship only fires bullets that I want. If spaceship needs more than 10 bullets at the time it creates new ones. Only problem is when my bullets gets deactivated my script never checks if there are any deactivated bullets of that type in hierarchy that my ship could reuse and instead just keeps making new bullets all the time. Im trying to achieve that my script would first check if there are any bullets it can reuse before creating new ones.
THIS IS PART OF MY SCRIPT
public GameObject GetObjectForType(string objectType)
{
for (int i = 0; i < entries.Length; i++)
{
var newPooledObject = entries[i].pooledObject;
if (newPooledObject.name != objectType)
continue;
if (pooledObjects[i].Count > 0)
{
GameObject newestPooledObject = pooledObjects[i][0];
pooledObjects[i].RemoveAt(0);
newestPooledObject.SetActive(true);
return newestPooledObject;
}
if (expandPoolAmount)
{
GameObject newestGameObject = Instantiate(entries[i].pooledObject) as GameObject;
newestGameObject.name = entries[i].pooledObject.name;
return newestGameObject;
}
}
return null;
}
AND THIS IS THE PART THAT I CAN’T FIGURE OUT
This is part from original script (supports only one type of bullets) that I’m trying to modify for more than one type of bullets.
The reason what you are trying to accomplish is not working is because you are exiting the function as soon as you found an object. Well anyway, if this was not an issue yet, it would of been eventually.
Anyhow, I took my Optimized Solution (a few post above) and made it so it suits your needs.
The method GetPooledObjects takes a bool parameter to determine if they should be auto activated or not.
By default it’s set to true… so just calling the method will automatically setActive the next inactive objects.
EDIT: Added the list expansion.
Hope this helps
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class MultipleObjectsPooling : MonoBehaviour
{
[System.Serializable]
public class Objects_Pool_Entry
{
public GameObject pooledObject;
public int pooledAmount = 1;
}
public Objects_Pool_Entry[] pooledEntries;
public bool expandPoolAmount = true;
List<GameObject>[] pooledObject;
void Start ()
{
pooledObject = new List<GameObject>[pooledEntries.Length];
for(int i = 0; i < pooledEntries.Length; i++)
{
pooledObject[i] = new List<GameObject>();
for(int j = 0; j < pooledEntries[i].pooledAmount; j++)
{
GameObject go = InstantiatePrefab(i);
}
}
}
GameObject InstantiatePrefab(int arrayIndex, bool autoActivate = false)
{
var go = Instantiate(pooledEntries[arrayIndex].pooledObject) as GameObject;
go.name = pooledEntries[arrayIndex].pooledObject.name;
pooledObject[arrayIndex].Add(go);
go.SetActive(autoActivate);
return go;
}
public GameObject[] GetPooledObjects(bool autoActivate = true)
{
GameObject[] tempArray = new GameObject[pooledObject.Length];
for(int i = 0; i < pooledObject.Length; i++)
{
for(int j = 0; j < pooledObject[i].Count; j++)
{
if(!pooledObject[i][j].activeInHierarchy)
{
tempArray[i] = pooledObject[i][j];
if(autoActivate)
pooledObject[i][j].SetActive(true);
break;
}
if(j >= (pooledObject[i].Count - 1))
{
if(expandPoolAmount)
{
GameObject go = InstantiatePrefab(i);
}
}
}
}
return tempArray;
}
}
Almost gave up on this but when I saw that someone (you) is actually willing to help me out I stick to it. It took me 5 days (12+ hours/day) to make it work. It’s a hard life if you are noob like me hehe.
Well I made my script to work exactly how I wanted. Still didn’t figure out your optimized version. Don’t know how to call the object from your script to even try it out… But your example did make me understand what I’m doing wrong and how to make it work.
Will give another try at your optimized version later when I learn a bit more about scripting hehe.
THANK YOU AGAIN SLUICE!!!
This is my final version
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class Objects_Pool : MonoBehaviour
{
public static Objects_Pool objectsPool;
[System.Serializable]
public class Objects_Pool_Entry
{
public GameObject pooledObject;
public int pooledAmount;
}
public bool expandPoolAmount = true;
public Objects_Pool_Entry[] entries;
public List<GameObject>[] pooledObjects;
void OnEnable ()
{
objectsPool = this;
}
void Start ()
{
pooledObjects = new List<GameObject>[entries.Length];
for (int i = 0; i < entries.Length; i++)
{
var objectpooledObject = entries[i];
pooledObjects[i] = new List<GameObject>();
for (int n = 0; n < objectpooledObject.pooledAmount; n++)
{
var gameObject = Instantiate(objectpooledObject.pooledObject) as GameObject;
gameObject.name = objectpooledObject.pooledObject.name;
PoolObject(gameObject);
}
}
}
public void PoolObject (GameObject newGameObject)
{
for (int i = 0; i < entries.Length; i++)
{
if (entries[i].pooledObject.name != newGameObject.name)
continue;
newGameObject.SetActive(false);
pooledObjects[i].Add(newGameObject);
}
}
public GameObject GetObjectForType(string objectType)
{
for (int i = 0; i < entries.Length; i++)
{
var newPooledObject = entries[i].pooledObject;
if (newPooledObject.name != objectType)
continue;
for (int n = 0; n <pooledObjects[i].Count; n++)
{
if(!pooledObjects[i][n].activeInHierarchy)
{
return pooledObjects[i][n];
}
}
if (expandPoolAmount)
{
GameObject newestgameObject = Instantiate(entries[i].pooledObject) as GameObject;
newestgameObject.name = entries[i].pooledObject.name;
pooledObjects[i].Add(newestgameObject);
}
}
return null;
}
}
Test out the scene… (Left mouse press will trigger the GetPoolObject)
Look at your inspector to see the Instantiate objects being toggled. By default there are only 1 of each prefab to show that the expandPool works. Obviously, you would set a few more normally…
Testing now… Only thing that is not for me is that when I pressed mouse button all 3 of them were activated at same time and I only want lets say circle. I need to be able to pool only 1 object from all different objects that are pooled at start.
I will have 1 player spaceship with 3 different weapon slots (one at front, one on left side, one on right side). When I press “Fire1” I want to shoot lazer bullet at front, when I press “Fire2” I want to shoot plazma on left side and when I press “Fire3” I want to shoot rocket on right side.
And also all enemies in the game will use same pool for their bullets that is why I tried so hard to make one big pool work.