TL;DR:
Add a text element to the scene, attach the SCRIPT below to it, and drag the Text object from the hierarchy to the “text” field.
SCRIPT:
using UnityEngine;
using UnityEngine.UI;
public class TestTimer : MonoBehaviour {
public Text text;
private string original;
private int startCount = 10;
private int endCount = 0;
// Use this for initialization
void Start () {
original = text.text;
StartCoroutine ("CountDown");
}
IEnumerator CountDown(){
while (startCount >= endCount){
text.text = original + "\n\nT-minus " + startCount--;
yield return new WaitForSeconds (1f);
}
text.text += "\n\n<color=#FF0000FF>LIFT OFF!\nLIFT OFF!\nLIFT OFF!</color>";
yield return null;
}
// Update is called once per frame
void Update () {
// Note the lack of code here.
}
}
Hi Simonas.
This is probably far beyond the scope of this course, but I’ll show it to you anyway. Hopefully, exposure to this will help you learn it faster than I did (in fact, I’m still learning).
You can use something called a Coroutine - Often used if you need to make adjustments over time (e.g. fade a word’s text colour from white to red - this won’t work easily in the update function), or if you need to perform timing operations (e.g. what you’re doing).
Basically, all the methods in the course so far have run from the beginning to the end (unless skipped by if/else if/else statements inside the method).
A Coroutine is different - it allows the user to execute part of a method, then it can wait for a specified time or for the next frame to do something else.
Here’s an example for you:
using UnityEngine;
using UnityEngine.UI;
public class TestTimer : MonoBehaviour {
public Text text;
private string original;
private int startCount = 10;
private int endCount = 0;
// Use this for initialization
void Start () {
original = text.text;
StartCoroutine ("CountDown");
}
IEnumerator CountDown(){
while (startCount >= endCount){
text.text = original + "\n\nT-minus " + startCount--;
yield return new WaitForSeconds (1f);
}
text.text += "\n\n<color=#FF0000FF>LIFT OFF!\nLIFT OFF!\nLIFT OFF!</color>";
yield return null;
}
// Update is called once per frame
void Update () {
// Note the lack of code here.
}
}
In order to use this script, add a text element to the scene, attach this script to it, and drag the object from the hierarchy to the “text” field.
This will make the example work (PLEASE tell me if it doesn’t work
)
Now to EXPLAIN the example:
using UnityEngine;
using UnityEngine.UI;
public class TestTimer : MonoBehaviour {
/* public Text text: declares a "text" component with the name "text" and
exposes it in the inspector (A component is something like "Transform",
"Rect Transform", ANY script you've added... and the inspector is where you
can manipulate these values. In this case, you can drag anything from the
hierarchy into the text field as long as it has a "Text" Component.
*/
public Text text;
/* private string original: declares a string (a value between
double quotes ==> <">) named "original". I'll be using this variable to store
the original value of whatever is stored in the text object, so it doesn't
get overwritten.
*/
private string original;
/* private int startCount and private int endCount: I start counting at 10, and
go down until I hit 0.
*/
private int startCount = 10;
private int endCount = 0;
// Use this for initialization
void Start () {
/* original = text.text: Stores the value already in the text object
("This is the Timer").
StartCoroutine ("CountDown"): as the name implies, this starts the Coroutine
named "CountDown". In Unity, you CAN call Coroutines like any other method,
or by passing in the function like this:
StartCoroutine (CountDown);
HOWEVER, I prefer the method below, because then you can use the
StopCoroutine() method to single out and stop the Coroutine you started.
*/
original = text.text;
StartCoroutine ("CountDown");
}
/* IEnumerator CountDown(): This is just a method declaration like any other.
HOWEVER, the "IEnumerator" signals to Unity that this method is a Coroutine.
*/
IEnumerator CountDown(){
/* while (startCount >= endCount): This is called a WHILE loop. I don't know
if you know about them, so I'll explain them here.
Basically, think of a <while> loop as an <if> statement that keeps
repeating until the condition is false.
The <while> loop will literally run "<while> (condition) is
true." The <while> loop can also be "escaped" with a "break;"
statement.
The condition is <startCount is "greater than or equal to" endCount>.
As long as startCount is AT LEAST larger than -1 (endCount - 1), this
code will run.
*/
while (startCount >= endCount){
/* text.text = original + "\n\nT-minus " + startCount--: This sets the
text to "This is the Timer\n\nT-Minus X" (where \n = new line and
X is startCount)
I don't know if you've seen -- or ++ before, SO:
If you have an integer (like startCount), you can automagically
increment it by saying "startCount++". This will "read" as
"startCount;
startCount = startCount + 1;"
Decrementing the number is the same: "startCount--" =
"startCount;
startCount = startCount - 1;"
One more gotcha: you can put the ++ and -- at the START
(e.g. --startCount) to automagically increment/decrement a number
BEFORE it is read.
*/
text.text = original + "\n\nT-minus " + startCount--;
/* yield return new WaitForSeconds (1f): This is where your timing magic
happens. Coroutines MUST have a return value. it can be
"yield return null", or another IEnumerator. In this case, I opted for:
"yield return new WaitForSeconds(1f);"
This tells the Coroutine to stop executing for the given number of
seconds (specified as a float - the "f" after the 1 stops Unity
reading it as an integer).
*/
yield return new WaitForSeconds (1f);
}
/* After the loop ends ("This is the Timer\n\nT-Minus 0"), the text will take
all existing text inside the object and add 2 newlines, then the words
"LIFT OFF!" in red, separated by newlines.
*/
text.text += "\n\n<color=#FF0000FF>LIFT OFF!\nLIFT OFF!\nLIFT OFF!</color>";
}
/* And Finally, most importantly of all:
I DID NOT USE UPDATE.
... Not that update is bad. It's just meant for things that should be done
every frame.
One other use for Coroutines is if you have something computationally heavy
(e.g. maybe you need to sort a list), using the update method or a standard
method could cause the game to hang.
If you wrap the operation in a Coroutine, even operating every 0.1f seconds,
it'll (hopefully!) improve execution time.
*/
// Update is called once per frame
void Update () {
// Note the lack of code here.
}
}
I hope this was accurate.
More importantly, I hope this has helped.