How to make WaitForSeconds work as a repeating/looping timer?

Hey folks. WaitForSeconds is bugging me again… I’m currently making a object pool that repopulates (re-enables) deactivated game objects every second or so.

Normally I’d use something like,

public     float timerLimit = 1.0f;
private    float timer = 0.0f;

void Update () {

    timer += time.deltatime;
    if(timer >= 1.0f){
        Debug.Log("Do stuff to populate level!");
        timer = 0.0f;
    }
}

…but I’m trying to break some old habits and use coroutines instead (I’ve been warned off using Invoke, as coroutines are more flexible).

However, upon using,

	public	float	populationRate	= 1.0f;

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

		StartCoroutine(SpawnLoop());

	}

	IEnumerator SpawnLoop () {

	yield return new WaitForSeconds (populationRate);

	Debug.Log ("Waited for " + populationRate + " seconds, and it's now " + Time.time);

	}

…and expecting a log like,

Waited for 3 seconds, and it's now 3.000000
Waited for 3 seconds, and it's now 6.000000
Waited for 3 seconds, and it's now 9.000000
Waited for 3 seconds, and it's now 12.000000
Waited for 3 seconds, and it's now 15.000000

…instead, I get a log like:

Waited for 3 seconds, and it's now 3.001297
Waited for 3 seconds, and it's now 3.072943
Waited for 3 seconds, and it's now 3.358437
Waited for 3 seconds, and it's now 3.466427
Waited for 3 seconds, and it's now 3.497489

My intent was to create a passive loop to check my current population and then do stuff - instead of actively consuming CPU time each Update (trust me, this isn’t a premature optimisation).

Is WaitForSeconds unsuitable for this? Is there a way to make it loop?

If I use a ‘while = true’ or ‘for’ loop in the coroutine, isn’t this basically the same as just sticking that code into Update and building a short timer?

Questions, Unity community! Questions! Do you have… ** answers?!?! **

Many thanks in advance,

–Rev

You need to remember that in coroutines you are responsible for setting up a loop and ending it.

IEnumerator SpawnLoop()
{
    while (enabled)
    {
        yield return new WaitForSeconds (populationRate);
        Debug.Log ("Waited for " + populationRate + " seconds, and it's now " + Time.time);
    }
}

The above code will stop executing when the MonoBehaviour is disabled.

Furthermore, you will be starting that coroutine every frame, which is a no-no, and is why you’re seeing results spit out every frame after a specified wait. You have n coroutines all waiting for that time limit before spitting something out to the log. Instead, start it in one of either the Awake or Start methods.