InvokeRepeating vs Coroutines: Run a method at certain time intervals
Sometimes you need to execute some tasks at certain time intervals. Or, sometimes, when you need expensive calculations, to prevent performance losses, you would like to decrease the frequency of the calculations. There are several methods to do this. In this article, we are going to learn three ways of doing this: InvokeRepeating, Coroutine, and Timer.
Using Invoke and InvokeRepeating
When you would like to run a method with a delay, you can use Invoke method. For instance, in the script which is below the Print method runs with a 2 seconds delay after the scene is started. The first parameter of the Invoke method has to be the exact same name with the method which will be executed. The second parameter is the delay time in seconds.
public class InvokeTest : MonoBehaviour { void Start(){ Invoke("Print", 2f); } void Print(){ Debug.Log("Method is executed"); } }
Likewise, if we need a method that runs periodically, then we can use InvokeRepeating. InvokeRepeating is similar to the Invoke. But this time, there is a third parameter and we determine the time intervals with this third parameter.
public class InvokeTest : MonoBehaviour { void Start(){ InvokeRepeating("Print", 2f, 1f); } void Print(){ Debug.Log("Method is executed"); } }
Here, the Print method will run with 2 seconds delay after the scene loaded and it will run once a second periodically.
Using Coroutine
The second way of running a code periodically with certain time intervals is using Coroutine. Coroutines allow us to delay the execution of a method. We use yield return statement to make the method wait.
public class CoroutineTest : MonoBehaviour { private IEnumerator coroutine; void Start(){ coroutine = Print(2f); } IEnumerator Print(float time){ while(true){ yield return new WaitForSecondsRealtime(time); Debug.Log("Method is executed"); } } }
Here, the Print method will run once 2 seconds after the scene is loaded. Actually, this coroutine is called immediately when the scene starts(since it is in Start) but WaitForSecond() pauses the execution for some time. To make this task periodically, we can use while loop as follows.
IEnumerator Print(float time){ while(true){ yield return new WaitForSeconds(time); Debug.Log("Method is executed"); } }
Sometimes you may need to stop the coroutine. This is easy by using StopCoroutine method:
StopCoroutine(coroutine);
Note that WaitForSecond is effected by the time scale in which your game runs. Thus, if you change the time scale, your wait time also changes according to real time. Nevertheless, if you would like to pause the execution of your method according to your clock, you can use WaitForSecondsRealtime( ).
Using Timer
The third way to execute a method in certain time intervals is to create a timer in Update. This way is not very effective and sometimes seems messy. Our intention to cover this method is just to give you some intuition about what you can do using only basic C# knowledge.
public class TimerTest : MonoBehaviour { float timer=0; void Update() { timer += Time.deltaTime; if(timer>2f){ Print(); timer = 0; } } void Print(){ Debug.Log("Method is executed"); } }
Here, we created a variable for timer and increase its value for every frame using Time.deltaTime. Time.deltaTime gives us elapsed time between two frames. Therefore, we can check the elapsed time from the last run, if we sum all elapsed times between frames. When the elapsed time is higher than our interval we execute the method and set the zero the timer.
InvokeRepeating vs Coroutine
As we mentioned above, you should not use a timer since they are not an effective way, unless you know what you are doing. On the other hand, Invoke and Coroutine seem similar and you may wonder when to use Invoke and when to use Coroutine.
Using an Invoke (or InvokeRepeating) is easier than using a coroutine. On the other hand, Coroutines are more flexible. You cannot pass a parameter to an invoked method but you can do this to a coroutine.
Another thing which we have to mention is coroutines are more performance-friendly than the Invoke. For basic games, it does not matter much but if you have several objects which do the same thing, you should consider using Coroutine instead of Invoke.
The last difference between Invoke and Coroutine which we will cover is the execution condition after the deactivation of the object. Invoke and InvokeRepeating do not stop after the game object is deactivated. On the other hand, this not true for coroutines. They stop after the game object is deactivated or destroyed. Therefore, you should use Invoke or InvokeRepeating, if you would like your method to continue running, even though the object is deactivated after the method is triggered.