- Home /
WaitForSeconds not (always) working on level startup
Hi, biiiiig noob here :)
I am trying to have a 3-2-1-GO! countdown on level startup. During the countdown, the time should be frozen.
This is what I have so far, and it's almost working:
void Start () {
countDownText.enabled = true;
offset = transform.position;
startCountdown ();
}
void LateUpdate () {
transform.position = player.transform.position + offset;
}
void startCountdown() {
StartCoroutine (getReady ());
}
IEnumerator getReady ()
{
float epsilon = 0.000001f;
Time.timeScale = epsilon;
countDownText.text = "3";
yield return new WaitForSeconds(1 * Time.timeScale);
countDownText.text = "2";
yield return new WaitForSeconds(1 * Time.timeScale);
countDownText.text = "1";
yield return new WaitForSeconds(1 * Time.timeScale);
countDownText.text = "GO!";
yield return new WaitForSeconds(1 * Time.timeScale);
Time.timeScale = 1.0f;
countDownText.enabled = false;
TimerUpdater other = (TimerUpdater) timerText.GetComponent(typeof(TimerUpdater));
other.ResetTimer ();
}
It's almost working in the sense that I have two scenes, a menu one and the game one (the game one contains the code above, the menu one is literally just OnAnyKeyPressed, Application.Load the other).
The game scene has a victory condition that brings you back to the menu one when met.
What happens now is that for the first 2-3 loops of menu, win, menu, win, everything works as intended. After a while, things start to go bananas, and in the moment the main game scene is loaded the countdown goes 3-2-1-go super fast (so fast you don't even see it without debug timestamps) and the game starts immediately.
Any hints?
Thanks,
D.
For some reason, changing the wait-one-seconds parts to:
float epsilon = 0.0001f;
Time.timeScale = epsilon;
countDownText.text = "3";
float nextTime = Time.time + epsilon;
while (Time.time < nextTime) {
yield return null;
}
Seems to fix it. I'm O$$anonymous$$ with it, but still baffled and I'd like to have some answer about the why :/
Hmmm, you wait for a millionth of a second, with time slowed to one millionth speed, so they cancel to be 1 second. Some other script probably reset timeScale to 1, causing the speedup.
I'd guess the second version works because you accidentally fixed the real problem elsewhere.
timeScale=0
is a poormans's pause. Once you have to start coding exceptions, seems easier to just use a pause variable for code, and freeze rigidbodies.
Hi Owen, thanks for your comment. I suspected that too but my game is very small (it's just an enhanced version of the roll-a-ball tutorial) and I'm sure there is no other place I alter the timeScale. From my noob point of view, I find the timeScale reduction far more elegant than putting a pause flag in every script, care to share why that approach is better?
The other place you alter the timeScale may be the same place. $$anonymous$$ake sure you don't have the coroutine running twice and use a string ins$$anonymous$$d:
StopCoroutine("getReady"); StartCoroutine ("getReady");
Owen's strategy is better because it's more extensible, allows the program to continue doing other things at regular speed while paused, and avoids any expensive or inaccurate floating point calculations.
If this isn't the case then the actual problem is probably Unity adding it's own millionth of a second to your float somewhere along the way. (it happens to me all the time and i dont know why. 5f + 5f will usually end up as 10.0000001f or 9.99999999f)
Should I call the StopCoroutine as the last line of the getReady function or where?
BTW, you should never test for equality using floats or double, due to their nature. Do something like if ($$anonymous$$ath.abs(v1 - v2) < epsilon) then v1 == v2 . I'm a Unity noob but I know a couple of program$$anonymous$$g tricks :)
Your answer
Follow this Question
Related Questions
Time.timeScale problem 1 Answer
how to stop object before GO writes 1 Answer
Press Key for higher TimeScale and WaitForSeconds for lower TimeScale 0 Answers
run level for 4 minutes help 1 Answer