2
\$\begingroup\$

is there a way to start another coroutine once the last coroutine is finish. I have a button that activates a coroutine, the button can be pressed any time you want, when pressed you activate a coroutine. However I notice that when you press the button twice the coroutine happens twice, which is not want I want. Is there a way to make sure that once my Boomerangeffect(coroutine) is activate the coroutine can't start (if button is pressed) until the present coroutine is finished.

public GameObject BoomerangOn, BoomerangOff;
public static int buttonCount = 4;
static int timesActivated =  0;

void Start()
{
    if (PlayerPrefs.HasKey ("boomerangbutton")) {
        buttonCount = PlayerPrefs.GetInt ("boomerangbutton");
    }
}

void Update()
{
    PlayerPrefs.SetInt("boomerangbutton", buttonCount);
}

public void Activated ()
{
    if(timesActivated < buttonCount)
    {
        timesActivated++;
        StartCoroutine(BoomerangEffect());
    }
}

IEnumerator BoomerangEffect()
{

        BoomerangOn.SetActive (true);
        yield return null;
        yield return new WaitForSeconds (10.0f);
        yield return null;
        BoomerangOn.SetActive (false);
        yield return null;
        BoomerangOff.SetActive (true);
        yield return null;
        yield return new WaitForSeconds (1f);
        yield return null;
        BoomerangOff.SetActive (false);
        yield return null;
}
\$\endgroup\$
2
  • \$\begingroup\$ Do you want pressing the button while the coroutine is active to queue-up another activation, to start automatically when the current one finishes? Or should the press just be discarded if the coroutine is still running? If you want queuing, do you want to queue some number presses (eg. at most one new activation) or unlimited? \$\endgroup\$
    – DMGregory
    Commented Oct 2, 2016 at 13:59
  • \$\begingroup\$ Likely only tangentially related to the question, but what's the deal with all these yield return null;? Are you sure you need them? \$\endgroup\$
    – Philipp
    Commented Jan 10, 2017 at 9:53

2 Answers 2

4
\$\begingroup\$

StartCoroutine returns a reference to Couroutine object. Assign it then you can simply check if that reference is null or not, if its null, start couroutine, and when the coroutine ends, set it back to null.

Coroutine boomerangEffectCoroutine;
public void Activated ()
{
    if(timesActivated < buttonCount)
    {
        timesActivated++;
        if(boomerangEffectCoroutine  == null)
             boomerangEffectCoroutine = StartCoroutine(BoomerangEffect());
    }
}
IEnumerator BoomerangEffect()
{
    // your stuffs
    boomerangEffectCoroutine = null;
}
\$\endgroup\$
1
  • 1
    \$\begingroup\$ +1 This is the pattern I use for these cases. The advantage of storing a reference to the coroutine instead of just a bool is that it gives you the flexibility to have another button/script that can abort the coroutine (if this is a safe and meaningful operation in the particular context), whereas with the bool solution, once the coroutine has fired, you don't have an easy way to refer to it again (so you have to fall back on StopAllCoroutines or matching it by method name) \$\endgroup\$
    – DMGregory
    Commented Jan 10, 2017 at 12:01
0
\$\begingroup\$

Just have a bool variable keeping track whether or not the coroutine has been started. The routine can only be called if this variable is false. When the coroutine is started, set the variable to true, when it is finished set it back to false.

Could look something like this:

...
private bool coroutineRunning = false;
...
public void Activated ()
{
    if(timesActivated < buttonCount && !coroutineRunning)
    {
        timesActivated++;
        StartCoroutine(BoomerangEffect());
    }
}

IEnumerator BoomerangEffect()
{
    coroutineRunning = true;
    BoomerangOn.SetActive (true);
    ...
    BoomerangOff.SetActive (false);
    yield return null;
    coroutineRunning = false;
}
\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .