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) {
    List list;
    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:

  1. Ensure you are using System.Timers.
  2. Create a new Timer with Timer timer = new Timer(delay); where delay is in milliseconds.
  3. We need to associate a delegate with the timer.Elapsed event. This event requires an object and a TimerEventArgs 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 my SendMessage function. Additionally we need to Stop the Timer and Dispose of it.
  4. The += operator is simply adding this anonymous function to the timer.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!