C# Spawner stops spawning after some time

We want the spawner to spawn for the duration of the game, but it will stop spawning about half though the level. Their are also unspawned groups in our object pool that never get spawned. Also we just updated unity to 5.2 when this started happening.

(Note: the objects highlighted in blue are the intended objects to be spawned by this specific spawner).

Spawner Script:

using UnityEngine;
using System.Collections;

public class SqiushySpawner : MonoBehaviour {

    public GameObject[] nets;
    public float minTime = 10.0f;
    public float maxTime = 25.0f;
   
    private int curNet = 0;
   
   
    void Start(){
        Invoke("Spawn", Random.Range(minTime,maxTime));
    }
   
   
    void Spawn(){
        //just copied your code here
        GameObject obj = NewObjectPool.instance.GetObjectForType (nets[curNet].name, true); // had "NetOfDeathV3 3" .. also assuming the prefabs have the correct names
        if (obj == null)
            return;
       
        obj.transform.position = transform.position;
        obj.transform.rotation = transform.rotation;
        obj.SetActive (true);
       
        curNet = Random.Range(0,12);
       
        if(curNet > nets.Length){
            curNet = 0;
        }
       
        Invoke("Spawn", Random.Range(minTime,maxTime));
    }
}

I imagine that you could just use a coroutine for that.

using UnityEngine;
using System.Collections;

public class SqiushySpawner : MonoBehaviour
{
   public GameObject[] nets;
   public float minTime = 10f;
   public float maxTime = 25f;

   private int curNet = 0;

   IEnumerator Start()
   {
      while(true)
      {
         yield return new WaitForSeconds(Random.Range(minTime, maxTime));

         GameObject obj = NewObjectPool.instance.GetObjectForType (nets[curNet].name, true);

          if (obj != null)
          {
              obj.transform.position = transform.position;
              obj.transform.rotation = transform.rotation;
              obj.SetActive (true);

              curNet = Random.Range(0,12);

              if(curNet > nets.Length)
              {
                  curNet = 0;
              }
           }
      }
   }
}

The above code should just wait, run, repeat forever. I, personally, also think it makes the intent of the code a bit more clear when it’s written this way. I hope that helps.

Thanks for the help, sadly though when tested only one group was spawned during the duration of the level.
I’m wondering why only one group? Perplexing.

Bump

Still need some help on this issue.

It could be because you are using the gameobject.name on line 19, maybe try using tags, as the names are in the format object1, object2, etc

While we are using gameobject.name because we need the object to return back to the object pool using it’s public static.

Public Static in Object pool:

public static NewObjectPool instance { get; private set; }

so to access this in the spawner, line 19 was written this way:

GameObject obj = NewObjectPool.instance.GetObjectForType (nets[curNet].name, true);

I did try to use GameObject.FindGameObjectsWithTag, but I got this error:

Any Idea how we can work this?

The problem hides inside the logic.

Your own code sample will stop spawning as soon as null is returned by ‘NewObjectPool.instance.GetObjectForType’. Noone except you knows under which circumstances ‘null’ will be returned.

The coroutine example does a little better, it doesn’t stop trying to spawn yet the problem still exists, as it won’t continue to execute the content of the if statement as soon as you will get an index that makes ‘NewObjectPool.instance.GetObjectForType’ return null.

The apparent reason:
The only chance (according to your code) to generate a new index is when the current index does not lead to a return value of ‘null’.
In other words, once null is returned, the index stays the same and the method will most-likely keep returning null for that index unless there’s another control outside of that script.

*Edit One more thing about this:

curNet = Random.Range(0,12);
if(curNet > nets.Length)
{
    curNet = 0;
}

It should be curNet >= nets.Length and thus could be simplified to

curNet = Random.Range(0, nets.Length);

Thanks the advice it put us a step closer to solving this. The spawner did spawn for a longer amout of time until an error came into the console, then it stopped spawning:

Updated version of the spawner:

using UnityEngine;
using System.Collections;

public class SqiushySpawner : MonoBehaviour {

    public GameObject[] nets;
    public float minTime = 10.0f;
    public float maxTime = 25.0f;
   
    private int curNet = 0;
   
   
    void Start(){
        Invoke("Spawn", Random.Range(minTime,maxTime));
    }
   
   
    void Spawn(){
        //just copied your code here
        GameObject obj = NewObjectPool.instance.GetObjectForType (nets[curNet].name, true); // had "NetOfDeathV3 3" .. also assuming the prefabs have the correct names
        if (obj == null)
            Invoke("Spawn", Random.Range(minTime,maxTime));

        obj.transform.position = transform.position;
        obj.transform.rotation = transform.rotation;
        obj.SetActive (true);

        curNet = Random.Range(0, nets.Length);
       
        Invoke("Spawn", Random.Range(minTime,maxTime));
    }
}

Not sure where to go from here, anymore advice?

Have you tried using InvokeRepeating?

https://unity3d.com/learn/tutorials/modules/beginner/scripting/invoke

I second the use of a coroutine for this…they always seem to give better results with anything time based.

Just wondering what other “control” would I add. I’m not sure where to go with that?

Yes, I did try that and it yielded the same result.

I didn’t have anything specific in mind, that was just an addition to how this could be avoided.
You could also just put the integer generating part outside of the null check so that it generates a new one all the time even though the current one made the method return null.
However, If you need to stick with that specific index and do not simply want to generate a new one, you’ll need to make sure that the pool object is ready again.

Thanks, we finally got the spawner to kept generating infinitely. However now we have run into another problem with the spawner. The Gameobjects need a delay between each spawn so they don’t spawn on top of each other. We just want one or two on screen at a time.

Current spawner code:

using UnityEngine;
using System.Collections;

public class SqiushySpawner : MonoBehaviour {

    public GameObject[] nets;
    public float minTime = 10f;
    public float maxTime = 25f;
   
    private int curNet = 0;

    void Awake ()
    {
        Invoke ("WillStartSpawn", 35f);
        //Debug.Log ("Spawner will start in ....");
    }

    void WillStartSpawn ()
    {
        StartCoroutine (Start ());
        //Debug.Log ("Spawning has started");
    }

    IEnumerator Start()
    {
        while(true)
        {
            yield return new WaitForSeconds(Random.Range(minTime, maxTime));
           
            GameObject obj = NewObjectPool.instance.GetObjectForType (nets[curNet].name, true);
            //Debug.Log("Squishy is spawned");


            if (obj != null)
            {
                obj.transform.position = transform.position;
                obj.transform.rotation = transform.rotation;
                obj.SetActive (true);

                curNet = Random.Range(0, nets.Length);

                StartCoroutine(ResetSpawn());
            }
        }
    }

    IEnumerator ResetSpawn ()
    {
        //Debug.Log ("Spawn will reset");

        yield return new WaitForSeconds(15f);

        StartCoroutine (Start ());
        //Debug.Log ("Spawn is reset");
    }
}

Bump…

The start coroutine will continue running even though you start the reset coroutine. You’ll actually start more and more coroutines (the first one) and they will all keep running because you’re using while(true).

Thanks, but I solved the overlapping problem by changing the min and max time on the spawner (kind of stupid that I didn’t do that before). but, since I solved the issue should I still worry about ?

Well, in theory (again depending on the circumstances under which the pool method returns null) you could eventually have tens or hundreds or potentially thousands of those coroutines running. I doubt that would happen, there will be a situation in which many of them cannot find an index for a pool object which is ready and thus won’t pass the null check, but anyway.

Even if that wasn’t a visual problem, it’s still unnecessary to have all those coroutines running in the background and if you play long enough that may even be noticeable (probably, but never tried it).
If you intend to only continue the Start coroutine after ResetSpawn has finished, then just remove the loop. The coroutines will still call each other like: Start calls ResetSpawn and ends, ResetSpawn calls Start and ends, Start calls ResetSpawn …

At the moment (disregarding that the objects in the pool may all be in use and null is returned by the pool method) it works more like: Start calls ResetSpawn and startes all over again due to the loop… ResetSpawn starts another one of the Start coroutine, you now have 2 of them running and both will start a Reset Coroutine. These both reset coroutines will each start a new Start coroutine, you now have 4 of them running, which will start 4 Reset coroutines… in theory there’s a risk of an exponential increase.

Ok, How would I remove the loop, with the current code?

Just remove the while(true) part and the appropriate curly brackets.

Thanks this worked splendidly. But, if you want can you help us with another issue on this post?http://forum.unity3d.com/threads/c-renderer-enabled-isnt-working.358127/