CoRoutines and the update function.

Currently I’m in the process of creating a tower defence game, right now I have a grid system where you can place towers down and enemies come in on certain rows and precede along the screen. In a script I have attached to the tower, the start function calls a coroutine which determines when the tower should fire a bullet:

	// Use this for initialization
	IEnumerator Start () {
		yield return StartCoroutine(StartShooting());
	}
	
	IEnumerator StartShooting(){
		while(shootOn==1){
			yield return new WaitForSeconds(shootTime);
			GameObject currentBullet = (GameObject)Instantiate(towerAttack,transform.position,Quaternion.identity);
			currentBullet.GetComponent<TowerBulletsScript>().bulletType=myType;
		}
	}

Now, I have a piece of code in the update function of the script which checks to see if an enemy is in the same row as the tower and then by setting shootOn=1 so the tower knows when to shoot. But what happens is that shootOn is set to 0 default when the game starts, the tower spawns and goes past the StartShooting function since shootOn is set to 0 but the update function will change it to 1 when there is something to shoot at:

	void Update () {
                ....Some other non relevant code.
		if(enemyRows[myRow] >= 1){
			shootOn=1; //There is something in our row
			StartCoroutine(StartShooting());
		}
	}

But what happens now is that StartShooting is called but it seems to bypass the WaitForSeconds portion of the function and the tower then fires 25 bullets per second when something is in it’s row.

I think the problem lies in the fact I can’t put yeilds in the update script due to it being a void function.

What would be the best solution to this problem, I look forward to hearing your advice :slight_smile:

I think each time you do the update () you start a new coroutine. You need to prevent a new Coroutine from being started until the first one is done. May be as simple as:

if(shootOn == 0 enemyRows[myRow] >= 1){

btw, maybe can use a bool instead of an int for shootOn.

But if I put this, won’t this just end the “while” loop in the StartShooting function and without a reference in update, it won’t start again?

Good point. But the essence of the problem is that you launch a new coroutine at every update, which is bad. There are several ways to handle this. You either want to only lanuch a coroutine when needed, (as I sort of demo’ed above) or have the CoRoutine always run, checking every second if it should shoot or not. For this you do not start it in Update, only in Start().

	// Use this for initialization
	IEnumerator Start () {
		yield return StartCoroutine(StartShooting());
	}
	
	IEnumerator StartShooting(){
		while(true){
			yield return new WaitForSeconds(shootTime);
                        if(shootOn == 1) {
			   GameObject currentBullet =  (GameObject)Instantiate(towerAttack,transform.position,Quaternion.identity);
			currentBullet.GetComponent<TowerBulletsScript>().bulletType=myType;
                        }
		}
	}
	void Update () {
                ....Some other non relevant code.
		if(enemyRows[myRow] >= 1){
			shootOn=1; //There is something in our row
		} else {
                  shootOn=0;// do not shoot
                }
	}

Edit: Got this to work, thanks for your advice :slight_smile: