Would a do ... while work in our coroutine?

What would be the drawbacks of doing the isFiring Coroutine like this?

IEnumerator FireContinuously()
{
    do
    {
        // fire the projectile and wait
    } while ( isFiring );
}

It depends.

One would be, you’ll need to monitor when you need to refire when isFiring is set to false.

It all depends on what you want to achieve and how you want it to act.

It will also always fire at least once - even if isFiring == false - because it only checks the condition after each loop.

To prevent that, you’d use a standard while as opposed to a do..while

while (isFiring)
{
    // do some firing
}

The difference here is that the standard while checks the condition before entering the loop

Okay I think my question was vague, i wasn’t asking about when/why to use ado...while vs a while.
In this video, the course teacher suggested this method of starting and ending the Coroutine that fires our little spaceship gun:

        if( isFiring && firingCoroutine == null )
        {
            // if isFiring... start coroutine
            firingCoroutine = StartCoroutine( FireContinuously() );
        }
        else if( ! isFiring && firingCoroutine != null )
        {
            // stop coroutine... or should it stop itself?
            StopCoroutine( firingCoroutine );
            firingCoroutine = null;
        }

Essentially starting a Coroutine, assigning it to a variable, so that we can stop that coroutine later on, when the isFiring property becomes null (when the ‘firing’ button is released).

My question is why go this route, when we could just exit the while loop when isFiring is false, and the Coroutine could simply end itself?

IEnumerator FireContinuously()
    {
        do
        {
            // Add a new projectile
            GameObject projectile = Instantiate(
                projectilePrefab, // instantiate the projectile
                transform.position, // instantiate at position of shooter
                Quaternion.identity, // no rotation 
                transform // parent to attach to
            );

            Rigidbody2D rb = projectile.GetComponent<Rigidbody2D>();
            if( rb != null )
            {
                rb.velocity = transform.up * projectileSpeed;
            }

            Destroy( projectile, projectileLifetime );

            
            yield return new WaitForSeconds( GetRandomFiringRate() );

        } while ( isFiring );
    }

Oh, I see. I suppose it may just be due to common practice. We don’t always run coroutines with loops like this, so it is not always possible to just set the flag. Common practice is to explicitly stop the coroutine.

Just setting isFiring to false will work but with the above you would still need to set the firingCoroutine to null. This could be done in the coroutine after the loop.

Ah gotcha. Common practice makes sense, and you’re right that this would be a good way to approach this sort of looping coroutine in the future. It’s showing us the ‘right’ way to do it! haha!

Thanks Bixarrio

I’m glad, bixarrio was able to help you. :slight_smile:


See also:

Not specific to coroutines, but the right way to do it isn’t always so. There’s a reason there are a bunch of ways to do everything. It’s contextual. It always depends on your needs and what you’re trying to accomplish. The right way quickly becomes shoving a square into a round hole in the wrong circumstance.

Coroutines are an Iterator/IEnumerator hack that Unity has made as a work-around for a pausing issue they had. As such, they are messy and don’t necessarily fit in to “the right way to do it”. They’re more of an “exception to the rule”, kind of thing.