- Home /
Object Pooling Dequeue GameObject NullReference
Learned Object Pooling from this guy https://www.youtube.com/watch?v=tdSmKaJvCoA and tried to apply it to my project.
I am object pooling child game objects of a prefab in one script then set their active state to true in another script.
This is my object pool code
[System.Serializable]
public class Pool
{
public string tag;
public GameObject prefab;
public int size;
}
public static ObjectPooler instance;
private void Awake()
{
instance = this;
}
public List<Pool> Pools;
public Dictionary<string, Queue<GameObject>> poolDictionary;
// Start is called before the first frame update
void Start()
{
poolDictionary = new Dictionary<string, Queue<GameObject>>();
foreach (Pool poolobject in Pools)
{
Queue<GameObject> QueuePool = new Queue<GameObject>();
for(int i = 0; i < poolobject.size; i++)
{
int pindex = Random.Range(0, 17);
Transform child = poolobject.prefab.transform.GetChild(pindex);
GameObject obj = Instantiate(child.gameObject);
obj.SetActive(false);
QueuePool.Enqueue(obj);
}
poolDictionary.Add(poolobject.tag, QueuePool);
}
}
public GameObject SpawnFromPool(string tag, Vector3 position, Quaternion rot)
{
GameObject objectToSpawn = poolDictionary[tag].Dequeue();
objectToSpawn.SetActive(true);
objectToSpawn.transform.position = position;
objectToSpawn.transform.rotation = rot;
objectToSpawn.GetComponent<NavMeshAgent>().enabled = true;
poolDictionary[tag].Enqueue(objectToSpawn);
return objectToSpawn;
}
This is the script that uses the object pooling code
ObjectPooler objectPooler;
public Transform[] spawnLocation;
// Start is called before the first frame update
void Start()
{
/*
Pindex = Random.Range(1, 17);
pesdestrianchild = Pesdestrians.transform.GetChild(Pindex);
Transform clone = Instantiate(pesdestrianchild, this.transform.position, this.transform.rotation);
clone.gameObject.AddComponent<PedestrianAI>();
clone.transform.parent = this.transform;
*/
objectPooler = ObjectPooler.instance;
StartCoroutine(Spawn());
}
IEnumerator Spawn()
{
while(true)
{
for (int i = 0; i < spawnLocation.Length; i++)
{
GameObject Clone = objectPooler.SpawnFromPool("Pedestrian", spawnLocation[i].position, Quaternion.identity);
Clone.transform.parent = spawnLocation[i];
Clone.GetComponent<PedestrianAI>().Destination = spawnLocation[i].transform.GetChild(0);
}
yield return new WaitForSeconds(80f);
}
}
In the end I keep getting 'NullReferenceException: Object reference not set to an instance of an object ' from this line: GameObject objectToSpawn = poolDictionary[tag].Dequeue(); I don't understand what's the problem.
Ins$$anonymous$$d of re-inventing the wheel, use an existing implementation of an object pool that already works. Like: https://github.com/Venom0us/UnityObjectPooler
Well, object pooling has many different faces. For example if you want to have like 3 pools for 3 different enemy types but each one just has an Enemy class attached, the pool you've linked would throw them all in one pool since it only distinguish based on the class type. He wants to distinguish different objects based on the tag. Also he wants a different preallocation count for the different pools.
I agree that this implementation isn't that great since it has this hardcoded "17 child object" constraint for the prefab which is really strange.
Personally I would put the queue inside the Pool class and create the dictionary to link the tags to the Pool instances.
Answer by Bunny83 · Nov 12, 2019 at 02:15 PM
If the error is really in that line you have mentioned the most likely reason is that your "ObjectPooler" Start method is called after your "other class" Start method that uses the pooler. That means the ObjectPooler script has not yet created the dictionary and you try to use it.
I don't see any reason why you couldn't move all your code from Start into the Awake method. You don't really communicate to other instantiated objects. When the scene is initialized, all assets / prefabs are already loaded as they are part of the project and not part of the scene.
Since your pool has a fix size and you force-reuse the oldest object no matter if it is still in use or not, you could have used a simple array and just use an incrementing index for each pool which you roll over when you reach the end. This would be way faster than doing a Dequeue and an Enqueue each time.
Like I mentioned in the comment above I would highly recommend to change your Dictionary to
Dictionary<string, Pool>
and include the queue / array (and the index when using an array) inside the Pool class. That way all information that belongs to one pool is grouped properly instead of having two seperate structures with related information.
Your answer
Follow this Question
Related Questions
Multiple Cars not working 1 Answer
Distribute terrain in zones 3 Answers
GUI Error: You are pushing more GUIClips than you are popping 0 Answers
Got a Error about reffering a object i can not fix 0 Answers