How can I spawn different GameObjects using IEnumerator?

Hi!

I’ve been searching all day and I still can’t find an answer, so let’s get straight to the point.
My game has two principal scripts that control everything, the first, named “Game_Controller” has access to score, and the second named “Object_Spawner”, is responsible for spawning GameObjects according to the score in Game_Controller.

If score > 5, Object_Spawner will spawn a different GameObject, it’s like creating a new wave of enemies.

For that, I’m using IEnumerator and coroutines to start and stop a wave, the first wave spawn seems to work fine, but the problem is when I start the second wave it will just spawn hundreds of objects at high speed. Please note that I’m using a random timer in order to spawn objects at random time. I think the issue with the second wave has something to do with the timer.

The problem is when I start coroutine diamond. Please if there’s something bad in my code please notify me, Im just 17.

Thaanks!

CODE (Object_Spawner):

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class Object_Spawner : MonoBehaviour {

	private float Timer;
	public GameObject wave_Cam;
	public Text wave_Text;

	public Transform spawner;
	public GameObject victim;
	public GameObject Clone;

	public Transform diamond_Spawner;
	public GameObject diamond_Obstacle;
	public GameObject diamond_Clone;

	public IEnumerator coroutine_Triangle;
	public IEnumerator coroutine_Diamond;

	// Use this for initialization
	void Start () {
		
		RandomTimer();

		coroutine_Triangle = Callvictim (); // Assign function to variable coroutine_Triangle
        StartCoroutine(coroutine_Triangle); // On start run Triangle coroutine

		coroutine_Diamond = callDiamond (); // Assign function to variable coroutine_Diamond
		StopCoroutine (coroutine_Diamond); // On start don't run Diamond coroutine

		// coroutine_Gear = callGear(); // Assign function to variable coroutine_Diamond
		// StopCoroutine (coroutine_Gear); // On start don't run Gear coroutine
	}

	void RandomTimer()
	{
		Timer = Random.Range(0.9f , 1.8f);
	}


	void spawnVictim(){ // Spawn Triangle function
			Clone = Instantiate (victim, spawner.transform.position, spawner.rotation) as GameObject;
			Clone.GetComponent<Rigidbody2D> ().AddForce (Vector2.left * 300);
	}

	void spawnDiamond(){ // Spawn Diamond function
		diamond_Clone = Instantiate (diamond_Obstacle, diamond_Spawner.transform.position, diamond_Spawner.rotation) as GameObject;
		diamond_Clone.GetComponent<Rigidbody2D> ().AddForce (Vector2.left * 380);
	}

	IEnumerator Callvictim() // Start Callvictim to spawn triangles by random time
	{
		//---------------------------------------------------------// WAVE ACTIVATOR
		wave_Text.text = "WAVE 1";
		yield return new WaitForSeconds (1);
		wave_Cam.SetActive (true);
		yield return new WaitForSeconds (2);
		wave_Cam.SetActive (false);
		//---------------------------------------------------------//

		while (true) {
			spawnVictim ();
			yield return new WaitForSeconds (Timer);
			RandomTimer ();
		}
			
	}

	IEnumerator callDiamond() // Start callDiamond to spwan Diamonds by random time **--PROBLEM--**
	{
		while (true) {
			spawnDiamond ();
			yield return new WaitForSeconds (Timer);
			RandomTimer ();
		}
	}
		
		

	public void stop_Coroutine_Triangle(){ // Stop top Triangle coroutine
		StopCoroutine (coroutine_Triangle);
	}

	public void start_Coroutine_Diamond(){ // Start top Diamond coroutine
		StartCoroutine (coroutine_Diamond);
	}

	public void stop_Coroutine_Diamond(){ // Stop top Diamond coroutine
		StopCoroutine (coroutine_Diamond);
	}



	void Update(){
	}
}

CODE (Game_Controller):

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Game_Controller : MonoBehaviour {

	public GameObject up_Plane;
	public int accessedCount;

	// Use this for initialization
	void Start () {
		access_Count (); // Execute function on start
	}

	void access_Count(){ // Get access to count int located in a different script
		accessedCount = up_Plane.GetComponent<GO_UP> ().count;
	}

	void check_points(){
		
		if (accessedCount > 2) { // Triangle wave
			Camera.main.GetComponent<Spawner_Up> ().stop_Coroutine_Triangle();
			Camera.main.GetComponent<Spawner_Down> ().stop_Coroutine_Triangle_2();
		}

		if (accessedCount > 4) {
			Camera.main.GetComponent<Spawner_Up> ().start_Coroutine_Diamond();
		}

		if (accessedCount > 5) {
			Camera.main.GetComponent<Hex_Spawn> ().enabled = true;
		}
	}
	
	// Update is called once per frame
	void Update () {
		check_points (); // Execute function to check points
		access_Count (); // Execute function to update points
	}

}

I think the problem is at IEnumerator callDiamond();

You haven’t provided any information or relative code to show what are the Spawner_Up and Spawner_Down components, which are used in check_points() method of Game_Controller.

However, I can only assume that they are related to the the Object_Spawner, since they contain methods of the same name, e.g. start_Coroutine_Diamond() .

What you are doing wrong is your’re starting coroutine_Diamond multiple times, once per frame to be exact, since you are calling check_points (), which starts this coroutine, from inside Update().

So, as soon as accessedCount > 4 becomes true, a new instance of coroutine_Diamond will be created and started, in every frame.

So, check if the coroutine has started, before starting it again. Something like:

//quick fix
    bool diamondStarted;

//etc...

         if (accessedCount > 4 && !diamondStarted) {
             Camera.main.GetComponent<Spawner_Up> ().start_Coroutine_Diamond();

            diamondStarted = true;  //reset to false at some point
         }

…you get the idea… Now that you know where the problem is, maybe you can find a better solution to this (better than my quick fix), since you have all the relevant code in front of you.