Search Unity

Pooling a (GameObject?) Particle System

Discussion in 'Scripting' started by MaximumSpice, Sep 17, 2019.

  1. MaximumSpice

    MaximumSpice

    Joined:
    Oct 25, 2018
    Posts:
    22
    Hi guys,



    I am stumped, I am trying to create a pooling system for an explosion that is a prefab (which I think means then it is a GameObject?) but what is on that GameObject is a partical of said explosion.



    I am using a modified version of a pooling system I already have working fine for creating enemy objects (prefabs). The problem occurs when (I think) Unity goes to return the object/explosion to the pool. The explosion happens, I have it time 5 seconds and after that send it back to its pool.



    I get a 'nullreferenceexception object reference not set to an instance of an object' from unity, which from doing research is about something is happening is null? (I assume it means the pool is null?) Unity directs me to my 3rd script below and is aimed at this section;

    Code (CSharp):
    1. private void Update()
    2.    {
    3.        lifeTime += Time.deltaTime;
    4.        if (lifeTime > maxLifetime)
    5.        {
    6.            pool.ReturnToPool(this.gameObject); // null exception here
    7.        }
    8.    }


    Should I be using a particle system instead of a gameobject through my code? I'm confused why it works for the rest of my setup but not this.

    Below is my code if that helps.



    Location control of where explosions happen:

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class ExplosionEnemySpawnerGameObjectPooled : MonoBehaviour
    6. {
    7.    [Header("Pool")]
    8.    [SerializeField]
    9.    private ExplosionEnemyObjectPool explosionPool; // change this
    10.      
    11.  
    12.  
    13.  
    14.    private void OnTriggerEnter(Collider other)
    15.    {
    16.        if (other.tag == "Shot" || other.tag == "Player" || other.tag == "Asteroid" || other.tag == "Enemies" || other.tag == "HunterEnemies")
    17.        {
    18.            var ExplosionsEnemy = explosionPool.Get();
    19.            ExplosionsEnemy.transform.rotation = transform.rotation;
    20.            ExplosionsEnemy.transform.position = transform.position;
    21.            ExplosionsEnemy.gameObject.SetActive(true);
    22.        }    
    23.    }
    24. }


    My pooling queue system:

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class ExplosionEnemyObjectPool : MonoBehaviour
    6. {
    7.    public GameObject explosionPrefabs;
    8.  
    9.    public static ExplosionEnemyObjectPool Instance { get; private set; }
    10.    private Queue<GameObject> objects = new Queue<GameObject>();
    11.  
    12.  
    13.    private void Awake()
    14.    {
    15.        Instance = this;
    16.    }
    17.  
    18.    public GameObject Get()
    19.    {
    20.        if (objects.Count == 0)
    21.            AddOjbects(1);
    22.        return objects.Dequeue();
    23.    }
    24.  
    25.    public void ReturnToPool(GameObject objectToReturn)
    26.    {
    27.        objectToReturn.SetActive(false);
    28.        objects.Enqueue(objectToReturn);
    29.    }
    30.  
    31.    private void AddOjbects(int count)
    32.    {
    33.        var newObject = GameObject.Instantiate(explosionPrefabs);
    34.        newObject.SetActive(false);
    35.        objects.Enqueue(newObject);
    36.  
    37.        #region GetComponentPooled
    38.        newObject.GetComponent<IExplosionEnemyPooled>().Pool = this;
    39.        #endregion
    40.    }
    41.  
    42. }
    my timer/re-queuer to send the object back to the pooler

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class ExplosionEnemyGameObjectPooled : MonoBehaviour, IExplosionEnemyPooled
    6. {  
    7.    private float lifeTime;
    8.    private float maxLifetime = 5f;
    9.    private ExplosionEnemyObjectPool pool; // change this
    10.  
    11.  
    12.    public ExplosionEnemyObjectPool Pool // this is a method, not variable, dont be confused. Not sure why not void? cos we return something?
    13.    {
    14.        get { return pool; }
    15.        set
    16.        {
    17.            if (pool == null)
    18.                pool = value;
    19.            else
    20.                throw new System.Exception("Bad pool use, this should only get set once!");
    21.        }
    22.    }
    23.  
    24.    private void OnEnable()
    25.    {
    26.        lifeTime = 0f;
    27.    }
    28.  
    29.  
    30.    private void Update()
    31.    {
    32.        lifeTime += Time.deltaTime;
    33.        if (lifeTime > maxLifetime)
    34.        {
    35.            pool.ReturnToPool(this.gameObject);
    36.        }
    37.    }
    38. }

    my interface:

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public interface IExplosionEnemyPooled
    6. {
    7.    ExplosionEnemyObjectPool Pool { get; set; }  
    8. }
     
  2. Adrian

    Adrian

    Joined:
    Apr 5, 2008
    Posts:
    1,066
    You'll always be pooling game objects. If you're using a particle system, that's just a component added to a game object and you can't pool components by themselves. Your problem seems to be elsewhere.

    When you get a null reference exception, it's sometimes hard to tell what exactly is null. Don't just assume, put a Debug.Log statement above the line and print out the variables to verify what exactly is null. Then try to follow back the variable to figure out why it ends up being null (likely it either never gets assigned or is assigned null, then follow where that null is coming from).

    Looking at the code, nothing immediately jumps out. Maybe you have multiple IExplosionEnemyPooled scripts on your prefab and only one gets the pool set? Or you have an instance in your scene that wasn't loaded from the pool and therefore the pool was never assigned?
     
  3. MaximumSpice

    MaximumSpice

    Joined:
    Oct 25, 2018
    Posts:
    22
    Okay thanks man. Still haven't found the problem, time to de-bug!