- Home /
Coroutine won't run sometimes and other times it runs.
Hello,
I have a coroutine that runs every time a level ends to load up the next level. In level 1, the coroutine runs smoothly, no problems and as expected (it doesn't depend on the NumberOfEnemies script below, the coroutine is called from somewhere else). However, in level 2, the coroutine runs the first line only and the rest is being ignored forever and I am not sure why.
I put some print out messages for debugging and it confirmed that the first line in the coroutine runs, the second line is never run.
Here is the coroutine:
public IEnumerator WinLevel()
{
Time.timeScale = 0.3f;
yield return new WaitForSeconds(1);
Time.timeScale = 0.01f;
CurrentPlayer.GetComponent<Player>().enabled = false;
guiManager.GUIWin();
}
Here is what calls the above coroutine:
public void CheckLevelWinCondition()
{
if (GameManager.instance.NumberOfEnemies > 1)
{
GameManager.instance.NumberOfEnemies -= 1;
}
else if (GameManager.instance.NumberOfEnemies <= 1)
{
StartCoroutine(GameManager.instance.WinLevel());
}
}
Any help would be appreciated, thank you very much in advance.
EDIT: I understand that when timeScale is set to 0.3 I am not waiting a real second, but more than that. It is intentional :). But even after 20 seconds it still not run.
interesting. could you include the exact print statements you used and the output ? what happens if you comment out the first timescale set ? what happens if you comment out the second one ? it might be interesting to print the current timescale as well at the top of the coroutine. it's suggestive that it works the first time but not the second. i'm wondering if Time.timeScale doesn't take effect immediately.
try adding a yield return null
just before the yield return new WaitForSeconds(1)
. that would allow the rest of the system to deal w/ the new timescale before encountering the time-delay.
I added Debug.Log("Ran"); at the top of the coroutine and Debug.Log("Second wait done"); after the yield return new WaitForSeconds(1);
The first level, I had the two statement printed out in the console. The second level, only "Ran" got printed and the other one as never printed out.
If I comment out the first line (the timeScale change to 0.3f) nothing happens. As if there is no code being run. If I comment the second line out (the wait for one second) I changed the code tot he below:
public IEnumerator WinLevel()
{
Time.timeScale = 0.3f;
//yield return new WaitForSeconds(1);
Debug.Log("Start");
Time.timeScale = 0.01f;
CurrentPlayer.GetComponent<Player>().enabled = false;
yield return new WaitForSeconds(0.1f);
Debug.Log("It ran");
gui$$anonymous$$anager.GUIWin();
}
First level, ran smoothly, no problems. The second level only "Start" got printed out and the rest never happened.
Lastly I tried adding the yield return null and on the first level it worked pretty well while on the second nothing happened, same problem.
it might be interesting to print the current timescale as well at the top of the coroutine. it's suggestive that it works the first time but not the second.
Actually the timeScale change works. The first line runs with no problems in both levels but in the second level, that is all what runs. The timescale changes and nothing else is run in that block of code.
What exactly is the point of those Time.timeScale statements? And does the coroutine work correctly if you comment them out?
This is the win condition, I wanted to slow down the game to give the player a "heads up" the game has been won and transition "loss of control" rather than all of a sudden the game disables the controls and a win menu appears.
I commented the first timescale and in the first level it ran with no problems (like with the timescale set to 0.3f). In the second level it didn't run after the wait.
I don't think changing the global timescale is a good idea, even if its intentional. Ins$$anonymous$$d of:
Time.timeScale = 0.3f;
yield return new WaitForSeconds(1);
why not just wait 3 seconds?
If you have components that depend on a timescale, then maybe try making your own public static float to act as a timescale. I think there might be some internal Unity methods that run accordingly with the global timescale, so it might be better to leave it untouched.
Because I wanted to add a slow-motion effect not only the 3 seconds wait.
Your answer
Follow this Question
Related Questions
How do I get into the data returned from a UnityWebRequest ? 2 Answers
Coroutines IEnumerator not working as expected 2 Answers
Returning an IEnumerator as an int? 1 Answer
SpeedBoost won't reset : Problem with either WaitForSeconds or Coroutine (Solved) 2 Answers
IEnumerator not looping correctly? 1 Answer