- Home /
StartCoroutine works once
Hi!
having a problem with StartCoroutine, it seems like it works only once.
the purpose of the code is to show 3..2...1... and then start the game after the player clicked resume (which is after he paused the game previously obviously) .
my code
if (resume.paused || restart.continueGame1)
{
StartCoroutine(smoothBack());
if (continueGame)
{
Time.timeScale = 1f;
resume.paused = false;
restart.continueGame1 = false;
continueGame = false;
}
IEnumerator smoothBack() {
Time.timeScale = scale;
three.SetActive(true);
yield return new WaitForSeconds( scale);
three.SetActive(false);
two.SetActive(true);
yield return new WaitForSeconds( scale);
two.SetActive(false);
one.SetActive(true);
yield return new WaitForSeconds( scale);
one.SetActive(false);
continueGame = true;
}
for the first time everything runs great, but when I try to run the" smoothBack() " for the second time and beyond it doesn't work.
need your help! thanks!
public class resume : $$anonymous$$onoBehaviour { public GameObject pauseCanvas; public static bool paused = false;
public void resume1()
{
paused = true;
}
}
What do you mean by "it doesn't work"? Does it get called? Add some logging if you're not sure.
Without seeing the whole of the first function, or knowing how/when it's called, it's hard to be sure... but there's something suspicious about what you have shown. It looks like the "if (continueGame)" bit is supposed to happen after smoothBack has returned, but it will in fact happen the first time that smoothBack yields.
by it doesn't work I mean the game calls the function however it display the 3...2...1.. for a split of a second ins$$anonymous$$d of three seconds as it was for the first time.
getting in the "if (continueGame)" conditional, spouses to happen only after displaying the 3..2...1.. and that's what is happing but, again, there are shown for only split of a second
As I suspected, it looks like you're misunderstanding how coroutines work. Your first function will not wait for smoothBack to finish. It does not "only happen after displaying the 3..2...1", it happens as soon as you display the "3" (because that's when the coroutine first yields). So as soon as you display the "3", Time.timescale is set back to 1 and so things happen faster than you want.
If you want to wait for smoothBack to finish before setting timescale back to 1, there are (at least) 3 approaches you can take:
1) turn the first function into a coroutine and use yield return StartCoroutine(smoothBack)
in it,
2) moved the contents of the if (continueGame)
block into another function which you call at the end of smoothBack.
3) move the stuff in the if (continueGame)
block to the end of the smoothBack function.
Answer by Bunny83 · Mar 25, 2019 at 12:46 PM
Your issue is line 7 in your first code snippet:
Time.timeScale = 1f;
When you call StartCoroutine your coroutine will immediately run up to the first yield statement before the StartCoroutine call returns. That means your coroutine has already set Time.timeScale to "scale". However when you come back and "continueGame" is true you set the Time.timeScale back to 1. Since you probably intended to set the timeScale to some very small (not 0) number that means each of the WaitForSeconds will only wait for one frame since you set the timescale back to 1.
Just remove that line and you should be fine. Though the coroutine should set the timeScale back to 1 at the end.
You don't seem to need your "continueGame " bool at all. It look like you assumed that StartCoroutine will somehow "wait" until the coroutine is finished. That's not true. The code after your StartCoroutine call runs immediately after the coroutine hits the first yield. That's why your first call kind of worked. It never entered the if statement. However you started a new coroutine every frame. Your code of starting the coroutine should look like this:
if (resume.paused || restart.continueGame1)
{
resume.paused = false; // ensures we only start the Coroutine once
restart.continueGame1 = false; // ensures we only start the Coroutine once
StartCoroutine(smoothBack());
}
And at the end of your coroutine you should set the timescale back to 1
// [ ... ]
yield return new WaitForSeconds( scale);
one.SetActive(false);
Time.timeScale = 1f;
}
Though instead of using that "tiny scale trick" you can now simply use WaitForSecondsRealtime. This does also work when the timescale is set to "0".