For my game I am currently using a countdown script that I found in a tutorial. The code is as follows: Code (csharp): // the textfield to update the time to private var textfield:GUIText; // time variables public var allowedTime:int = 90; private var currentTime = allowedTime; function Awake() { // retrieve the GUIText Component and set the text textfield = GetComponent(GUIText); UpdateTimerText(); // start the timer ticking TimerTick(); } function TimerTick() { // while there are seconds left while(currentTime > 0) { // wait for 1 second yield WaitForSeconds(1); // reduce the time currentTime--; UpdateTimerText(); } // game over } However the code shown above is incomplete and doesn't do anything when it's gets to zero. What would I add to the code so that the level would start again? I know it would be something along the lines of application.LoadLevel(1) but other than that I have no idea where to even start. Can anyone help me?
I don't see any code that specifies what should happen when time gets at 0, so how you expect something to happen if you don't declare it. For as far I can see, the script only subtracts 1 from the currentTime (every second) as long as the currentTime is greater than 0.
psuedo code: if (currentTime <= 0) { Application.LoadLevel(1); } In fact its not pseudo hehe, it should work as long as currentTime reaches 0.
Sorry I'm a complete newbie when it comes to scripting. So I'd just add that on the end of the script I have?
You could put that piece of code in your Update function, like I said it should work as long as currentTime actually reaches 0. To check this, you could write a code like this: if (currentTime <= 0) { Debug.Log("current time is 0"); } So basically it's the same condition, only the code that gets executed is different. But this is very easy and useful to check the value of your variables. By the way. Use Awake to initialize variables, use something like function Update to actually run code and call functions to be executed. Update gets called every frame, Awake just once at creation of the object (so whenever you press play or instantiate the game object). Edit: I actually wrote a little script but it doesn't do what I expect it to do. I tried something similar before and it works but this time the function gets called every frame and the yield statement gets ignored. This is what I did: Code (csharp): public var currentTime : int = 90; function Update () { CountDown(); if (currentTime <= 0) { Debug.Log("Time is up my friend"); } } function CountDown() { currentTime = currentTime - 1; yield WaitForSeconds(1); }
Ok I'll just jack the thread then since RANDOM++ asked for help. There's nothing wrong with this code (other than formatting issues, but that's just personal bias, ignore me). The function will iterate through the 'while' loop until currentTime is no longer greater than 0, at which point the loop will no longer run. Since code gets executed sequentially, add something after the "game over" comment and it should execute at such a time. In code Code (csharp): function TimerTick() { // while there are seconds left while(currentTime > 0) { // wait for 1 second yield WaitForSeconds(1); // reduce the time currentTime--; UpdateTimerText(); } // game over <--------------This is where you do stuff Application.LoadLevel(0); //Or whichever level you want to load }
The problem with this particular code is that first of all, the yield statement is after whatever function you wanted to do, so it looks like the program is ignoring the yield statement. Second, you're calling CountDown() every frame, which means every frame it counts down the time by 1, then waits for one second. Even if you would flip the instructions, that still fires off the function every frame, so you'd have one second of nothing, and then every frame currentTime would count down by 1. Coroutines are executed at the same time (I assume in separate threads) after all. Instead, if we were to go along with your train of thought, we'd have to do something like this Code (csharp): public var currentTime : int = 90; function Start(){ CountDown(); } function CountDown() { while( true ){ currentTime = currentTime - 1; yield WaitForSeconds(1); } } function Update(){ if (currentTime <= 0) { Debug.Log("Time is up my friend"); } } Alternatively, there's a very nice function to repeatedly call a function for us in Unity Code (csharp): public var currentTime : int = 90; function Start(){ InvokeRepeating( "CountDown", 0, 1 ); } function Update () { if (currentTime <= 0) { CancelInvoke( "CountDown" ); Debug.Log("Time is up my friend"); } } function CountDown() { currentTime = currentTime - 1; }
Well, no, you're right...it's objectively harder to read and should be fixed. No, coroutines aren't threads; all code including coroutines is run in the main thread unless you explicitly create threads yourself with the System.Threading functions. But yes, what's actually happening is that a new instance of CountDown is being launched every frame in Update. The results are no different from just having Code (csharp): function Update () { currentTime = currentTime - 1; } except less efficient. Almost. The Update function should be removed; there's no reason to check the timer every frame when you're already decrementing it in the CountDown function and can just check it there. Also InvokeRepeating has an issue where in some cases it's called twice in the same frame if the initial timer is 0, so I always use something like .001 instead. Although in this case it should probably be 1 anyway. Code (csharp): public var currentTime : int = 90; function Start(){ InvokeRepeating( "CountDown", 1, 1 ); } function CountDown() { if (--currentTime == 0) { Debug.Log("Time is up my friend"); CancelInvoke( "CountDown" ); } } --Eric
I'd like to thank the both of you for your excellent help. I was confused why this wouldn't work, and in some other case I did almost the same in the update function and the coroutine function got executed perfectly. So I'm still not sure what's the reason for that. Now I use this piece of code and yeah it does do exactly what you want it to do Code (csharp): public var currentTime : int = 90; function Start(){ InvokeRepeating( "CountDown", 1, 1 ); } function CountDown() { if (--currentTime == 0) { Debug.Log("Time is up my friend"); CancelInvoke( "CountDown" ); } } But just for my understanding, the InvokeRepeating takes 3 parameters? The function to invoke, the endpoint where the InvokeRepeating function quits, and the time interval? And the CountDown function itself, I understand it's constantly checking if currentTime is equal to 0, I think I also understand why you wrote --currentTime. Everytime this function gets called (and the InvokeRepeating function says every second) currentTime gets subtracted by 1. Pretty cool it can be this easy, I wouldn't have come up with this myself Thanks thanks thanks @ Jack, the code provided by Eric works, you just need to change the Debug.Log statement to a Application.LoadLevel. I hope this also works out for you I did my best for you but I'm sorry if I lack some knowledge. At least I learned something after all this
The function, the time between now and the first instance of the invoke, and interval between invoke thereafter InvokeRepeating doesn't quit by itself. You'd have to call CancelInvoke somewhere in the same script to stop invoking
But ofcourse how could I be this stupid that was pretty obvious but still thanks for pointing out I just would forget something like that I'm sure I will find tons of uses for these functions because the projects I'm working on rely heavily on time intervals, I cherish every line I have to write less to achieve the same functionality.