Having trouble with pooling multiple lists of game objects

I’ve recently learned about the benefits of pooling game objects and recycling them over instantiating and destroying them. Unity has a nice tutorial for this but it dealt only with pooling just one object and I’d like a system that lets me pool multiple different objects. Can’t quite get it to work though. Here is the object pooling script I have so far:

public GameObject[] objects;
    public int[] number;

    public List<GameObject>[] pool;


    void Start () {

        instantiate();
   
    }
   

    void instantiate(){

        GameObject temp;
        pool = new List<GameObject>[objects.Length];

        for(int count = 0; count < objects.Length; count++){

            pool[count] = new List<GameObject>();

            for(int num = 0; num < number[count]; num++){
                temp = (GameObject)Instantiate(objects[count]);
                temp.transform.parent = this.transform;
                pool[count].Add(temp);
            }

        }

    }

    public GameObject activate(int id){

        for(int count = 0; count < pool[id].Count; count++){

            if(!pool[id][count].activeSelf){

                pool[id][count].SetActive(true);
                return pool[id][count];

            }
        }

        return null;
    }

I plug my bullet prefab into the first element in the list and then set how many of them I want instantiated. No problem. The only error I’m getting is from my shoot script:

public ObjectPooler pool;

    private Transform myTransform;

    private Transform cameraHeadTransform;

    private Vector3 launchPosition = new Vector3();

    public float fireRate = 0.2f;

    public float nextFire = 0;

    // Use this for initialization
    void Start () {
   
        myTransform = transform;

        cameraHeadTransform = myTransform.FindChild("BulletSpawn");

    }
   

    void Update () {

        if(Input.GetButton("Fire1") && Time.time > nextFire){

            nextFire = Time.time + fireRate;

            launchPosition = cameraHeadTransform.TransformPoint(0, 0, 0.2f);

            GameObject current = pool.activate(0);

            current.transform.position = launchPosition;
            current.transform.rotation = Quaternion.Euler(cameraHeadTransform.eulerAngles.x + 90,             myTransform.eulerAngles.y, 0);

        }
   
    }

Pressing the Fire1 button gives prompts:
“NullReferenceException: Object reference not set to an instance of an object” for line 33. Any ideas whats going on?

  1. You’re not handling a situation where there are no bullets left in the pool. This would result in null.

  2. I dont see you returning the bullets to the pool anywhere. It would most likely be handled by a script on your bullet though, so maybe you are.

I havnt tried to confirm the rest of the code is correct, but youre missing the above at a minimum

I got it figured out. I forgot to set the bullet prefab to disabled by default. A bit embarrassing

I am facing another issue, though. My object recycling is working great now but my bullets are acting strange. Literally every other bullet will pass through colliders and ignore the coroutine to disable itself. The bullet will just continue flying through the scene. As in, the first bullet is fine but the next will ignore colliders and the self disable coroutine, the next bullet is fine, bullet after that acts weird, etc. These “missed bullets” also remain active in the Object Pool list in the hierarchy. This DOESN’T appear to happen when I just instantiate the bullets instead of enabling/disabling them from the pool. What about my pooling system could be causing this behavior? Here’s the bullet script if it helps:

public GameObject hitEffect;

    private Transform myTransform;

    public float bulletSpeed = 0.1f;

    private bool spent = false;

    private RaycastHit hit;

    public float rayRange = 1.5f;



    // Use this for initialization
    void Start () {

        myTransform = transform;



    }
 
    // Update is called once per frame
    void Update () {

        myTransform.Translate(Vector3.up * bulletSpeed * Time.deltaTime);

        if(Physics.Raycast(myTransform.position, myTransform.up, out hit, rayRange)&&
           spent == false){

            if(hit.transform.tag == "Floor"){

                GameObject newHitEffect = (GameObject)Instantiate(hitEffect, hit.point, Quaternion.identity);

                Destroy(newHitEffect, 2);

                spent = true;

                gameObject.SetActive(false);

            }

        }
 
    }

And the revised object pooler:

public GameObject[] objects;
    public int[] number;

    public List<GameObject>[] pool;


    void Start () {

        instantiate();
  
    }
  

    void instantiate(){

        GameObject temp;
        pool = new List<GameObject>[objects.Length];

        for(int count = 0; count < objects.Length; count++){

            pool[count] = new List<GameObject>();

            for(int num = 0; num < number[count]; num++){
                temp = (GameObject)Instantiate(objects[count]);
                temp.transform.parent = this.transform;
                pool[count].Add(temp);
            }

        }

    }

    public GameObject activate(int id){

        for(int count = 0; count < pool[id].Count; count++){

            if(!pool[id][count].activeSelf){

                pool[id][count].SetActive(true);
                return pool[id][count];

            }
        }

        pool[id].Add((GameObject)(Instantiate(objects[id])));
        pool[id][pool[id].Count - 1].transform.parent = this.transform;
        return pool[id][pool[id].Count - 1];
    }