Timers vs Coroutines in Unity
If you have ever needed to delay a function before you’ve probably heard about Coroutines in Unity. After all they seem to crop up in the top hits on almost all of the Google searches I performed. That isn’t really a problem Coroutines are pretty awesome, I even wrote a video tutorial that relied heavily on Coroutines. I do realise they can be a little messy but for the most part they work well, and are also required as they are the only way to run methods over multiple frames in Unity. That statement isn’t entirely true, but it is the only way to run code over multiple frames outside of the Update loop when accessing the Unity API. Put simply it isn’t thread safe so we aren’t allowed to run Unity related activities in a threaded fashion.
But I am digressing a little bit here, why would I want to use Timers if Coroutines already exist? Well the StartCoroutine method can only be called on a MonoBehaviour and they can not exist without a GameObject. This can get a little tricky if we want to delay non-MonoBehaviour related code. In my specific case I wanted to be able to delay calls in a static helper class even though I wanted to pass the information immediately. This can be particularly useful if you want to dispose of the GameObject that is calling the static helper method, such as when using a decoupled messaging service.
Some digging revealed that the Timer class in c# is available for use in Unity and is non blocking which means we can start it and still run other game related code which is extremely important. Below is a code sample that shows how it works.
//Send a message to registered members with no parameters public static void SendMessage(MessageConstant messageType) { Listlist; if (_messageList.TryGetValue(messageType, out list)) { foreach (var action in list) { action(); } } } //Sends a message to registered members with no parameters after the specified delay public static void SendMessageWithDelay(MessageConstant messageType, float delay) { Timer timer = new Timer(delay); timer.Elapsed += (_, __) => { SendMessage(messageType); timer.Stop(); timer.Dispose(); }; timer.Start(); }
As you can see it is a fairly simple process which I will outline below:
- Ensure you are
using System.Timers
. - Create a new
Timer with Timer timer = new Timer(delay);
wheredelay
is in milliseconds. - We need to associate a delegate with the
timer.Elapsed
event. This event requires anobject
and aTimerEventArgs
paramater. I have no need for these so what I am going to do is create an anonymous function which takes both of those paramaters and does nothing with them. The body of the anonymous function will call mySendMessage
function. Additionally we need toStop
the Timer andDispose
of it. - The
+=
operator is simply adding this anonymous function to thetimer.Elapsed
event however we haven’t yet started running the Timer, so make sure you do that in your delay method as well.
It really is that simple, of course you don’t need to pass in an anonymous function you could write a more explicit one or actually use the parameters passed to the event but I personally had no need for them in this instance.
I’ve also created a short (~4 minute) video showing how it works. So just remember next time you need to delay something and it isn’t a MonoBehaviour you do have other options!