Problem using a bool to hold IEnumerator

I am trying to wait until a condition is true before continuing with my IEnumerator script. Here is what I have so far:

   public IEnumerator DeathScreenActivator()
    {
        yield return new WaitForSeconds(3.9f);

        magicXPIcon.gameObject.SetActive(true);

        magicXPText.text = magicXP.ToString();

        shouldCountDownMagicXP = true;

        while (!shouldCountDownMagicXP)
        {
            yield return null;


            Debug.Log("Now waiting 2 seconds.");

            yield return new WaitForSeconds(2f);

            Debug.Log("Now animating bottle.");



            yield return new WaitForSeconds(3f);

            if (isTut)
            {
                Destroy(PlayerController.instance.gameObject);
                SceneManager.LoadScene("Tutorial");

            }
            else
            {
                PlayerController.instance.gameObject.SetActive(false);
                SceneManager.LoadScene(mainMenuScene);

            }
       
        }
       
    }

Once shouldCountDownMagicXP is true, I have another script running elsewhere. When it is done, shouldCountDownMagicXP is set to false. But the while loop never runs (“Now waiting 2 seconds.” print never appears).

What am I doing wrong here?

Problem is with code execution order. What happens is this:

  • you start your DeathScreenActivator in a coroutine I presume like StartCoroutine(Fade());

  • after waiting 3.9s

  • you set shouldCountDownMagicXP = true

  • start while loop checking if it is falsy. ←

That’s your problem. Setting value to true and starting the loop with conditional is executed in a synchronous manner. In plane language condition check is performed right after you have set the value to true.

You have 2 problems.

  • While loop in your code will never run.
  • Whatever code you run (from “somewhere else”) didn’t have a chance to change the value of shouldCountDownMagicXP before condition check.
1 Like

Okay so basically I am trying to get the ienumerator to pause until a timer runs out. That’s what the other script is doing, the timer.

So is this not the right way? My research is telling me to start a while loop within the ienumerator for this task.

You set the shouldCountDownMagicXP to true and next line you test it for false. It will never enter the while loop. Actually i think the IDE will even warn that you have unreachable code.

It’s a short piece of code but I can already see few anti-paterns, namely naming, mixing sync/async behaviour in an uncontrolled way.

How do you trigger the other script (update, event)?

Could you paste the script from the other file as well? Before I give you any hints I would like to see what exactly are you trying to achieve to avoid sending you down the rabbit hole. I have a simple solution in mind but would like to see the full picture. Best if you describe it step by step what you want to achieve.

Ok so I did a lot of adjustment. I gave up on the while loop, and basically made it more code but simpler and have two different ienumerators happening instead, with the bool condition wrapping the second ienumerator. It’s not as clean but it’s easy!

Thanks for all the suggestions!

@jleven22 glad you sorted it but to be honest I would be tempted to send you to documentation to help you better understand how coroutine works in Unity but in the nutshell it makes use of C# features like yield keyword used by IEnumerable and its IEnumerator allowing to iterate over collections. When yield is encountered in the code it returns the value from the current iteration step, coroutine takes advantage of that and delays execution of the next line to the next frame.

Consider two simple pieces of code

using System.Collections;
using UnityEngine;

public class CounterBehaviour : MonoBehaviour
{
    private void Start()
    {
        StartCoroutine(FramePing());
    }

    public IEnumerator FramePing()
    {
        int counter = 10;
        while (counter > 0) {
            Debug.Log($"counter: {counter} frame: {Time.frameCount}");
            // yield return counter;
            counter--;
        }
        yield return null;
    }
}

and another script

using UnityEngine;

public class AnotherBehaviour : MonoBehaviour
{
    void Update()
    {
        if (Time.frameCount <= 10) {
            Debug.Log($"Update from another on frame: {Time.frameCount}");
        }
    }
}

Set these on the same object and run it, look at the logs.

Then uncomment line 16 in CounterBehaviour, run it again and compare the logs. That will explain the issue you are dealing with.

1 Like