How to delay a function in Unity

In Unity by John French6 Comments

Even if you’re new to Unity, calling a function can be very straightforward.

Simply call the function using its name, and it will be triggered immediately.

However, what if you don’t want to do something immediately?

What if you want to do something in one second’s time?

Or every half a second?

Or every minute?

There are a lot of different ways you could delay a function in Unity and, while they are all, typically, very straightforward, it can sometimes be tricky to know which method you should use.

In this article, you’ll learn the different ways to delay a function by an amount of time, so that you can choose the method that’s right for your project.

So, how can you delay a function in Unity?

How to delay a function in Unity

Normally, the code that you write will be executed line by line, in order.

Some functions will be called before others, like Unity’s event functions, for example, such as Update, and On Enable, which are called in a specific order.

And some events will be called before the same events on other scripts, in a, seemingly, random order, but one that can be controlled using the Script Execution Order Settings.

The Script Execution Order settings in Unity allow you to modify when a script is executed, relative to its Default Time.

However, even though functions and code are executed in order, most of your code will generally happen during the frame it’s called in.

Meaning that, if you want to delay a block of code in your game, or call a function in a few seconds’ time, you’ll need to find a way to delay the execution of that method.

So how can you?

Generally speaking, there are three main ways to delay a function in Unity:

  • You can call the function using the Invoke method, which allows you to schedule a function to be called in an amount of time,
  • You can yield the execution of a block of code using a Coroutine,
  • Or you can measure a time delay manually, using a Script.

How to use Invoke to delay a function

The purpose of the Invoke function is to call a method with a delay.

It works by passing in a String parameter, which is the name of the function that you want to call, and a Float delay, which is how long you want to wait before the function is triggered.

Like this:

void Start()
{
    Invoke("MyFunction", 3);
}
void MyFunction()
{
    Debug.Log("Hello!");  
}

Invoke works on the script you call it on, meaning that you can use it to trigger a function in the same script or to trigger a function on a different script that you have a reference to.

Like this:

public OtherScript otherScript;
void Start()
{
    otherScript.Invoke("MyFunction", 5);
}

And, because Invoke is a function of the script that holds the method, not the script triggering it, its possible to call private functions on other scripts using Invoke.

How to cancel Invoke

You can cancel an already triggered Invoke function, before the method is executed, by using Cancel Invoke.

Like this:

CancelInvoke("MyFunction");

Which will cancel any invoked function called by the class with the matching string name.

Or, Like this:

CancelInvoke();

Which will cancel all invoked functions on the class, regardless of what they’re called.

While Invoke can be very convenient it does have a couple of drawbacks.

For example, because the function is triggered by a string, it’s possible to break the connection if its name is ever changed.

What’s more, a method triggered using Invoke can’t accept parameters.

Meaning that, if you want to delay a function, but also pass data into it, you might want to consider using a Coroutine instead.

How to use a Coroutine to delay a function

Coroutines split functionality over a number of frames.

Meaning that while, normally, an entire function is executed during one frame, when using a Coroutine, it’s possible to break it up into different steps using Yield Statements.

Yield statements allow you to pause the execution of a block of code until the next frame, until something else happens or until an amount of time has passed.

For example, it’s possible to yield for an amount of time using the Wait for Seconds class, like this:

void Start()
{
    StartCoroutine(WaitForFunction());
}
IEnumerator WaitForFunction()
{
    yield return new WaitForSeconds(3);
    Debug.Log("Hello!");  
}

While Coroutines can be extremely useful for splitting up logic between frames, they’re not quite as convenient as using Invoke.

What’s more, while they are, generally, very efficient, Coroutines do create a small amount of Garbage. Once when they’re first started and, depending on how you do it, again whenever they are suspended.

In which case, if all you want to do is delay something by a couple of seconds, you may find it easier to simply measure the delay yourself, using a Script.

How to delay code using a Script

In Unity, it’s possible to measure time by adding up each frame’s Delta Time, which is the amount of time, in seconds, that it took to process the previous frame, allowing you to compare the amount of time that’s currently elapsed to a required delay value.

Like this:

public float delay = 3;
float timer;
void Update()
{
    timer += Time.deltaTime;
    if (timer > delay)
    {
        MyFunction();
    }
}
void MyFunction()
{
    // Do something!
}

Then, if enough time has passed, the function will be called.

This method works because the timer is continuously checking to see if it’s time to do something or not.

However, like this, the script will endlessly trigger the function as soon as the required amount of time has come and gone.

Meaning that, to prevent the function from being called more than once, you’ll need to, either, wrap the time code in an if condition…

Like this:

public float delay = 3;
float timer;
bool running = true;
void Update()
{
    if (running)
    {
        timer += Time.deltaTime;
        if (timer > delay)
        {
            MyFunction();
            running = false;
        }
    }
}
void MyFunction()
{
    // Do something!
}

Or, if you only need the script to do something once, turn it off as soon as you’re done with it.

Like this:

public float delay = 3;
float timer;
void Update()
{
    timer += Time.deltaTime;
    if (timer > delay)
    {
        MyFunction();
        enabled = false;
    }
}
void MyFunction()
{
    // Do something!
}

This method is simple, doesn’t create any garbage, and allows you to pass in parameters to the method you call.

Its drawback is that, because Update is called every frame, you’ll need to check every frame if it’s time to do something.

Even if you only do it once.

But what if you don’t want to do something just once?

What if you want to do something repeatedly, every second?

How to trigger a function repeatedly, every second, in Unity

In Unity, there will often be times when you want to trigger a function repeatedly, such as every second, or every fraction of a second.

The method of calling a function regularly like this is similar to the process of delaying a function for an amount of time, except that, instead of doing it just once, you’ll be triggering the function at timed intervals, over and over again.

In which case, because you no longer need to worry about finding a way to disable the process once it’s performed its delayed function, the Script Method of using a timer to measure a delay manually can be ideal for triggering a function at regular intervals.

How to trigger a function at regular intervals (using a Timer Script)

Triggering a function regularly using a timer in a script works in much the same way as delaying a method.

First, you’ll need to add up each frame’s delta time in Update and then compare it against the delay duration that you want.

The difference is, that, instead of disabling the script or turning off the timer when you’re finished, you’ll need to reset it instead, so that it can fire with a delay again.

Generally, the best way to reset a timer so that it triggers at regular intervals is by subtracting the interval duration you want from the elapsed time.

Like this:

public float delay = 0.2f;
float timer;
private void Update()
{
    timer += Time.deltaTime;
    if (timer > delay)
    {
        MyFunction();
        timer -= delay;
    }
}
void MyFunction()
{
    // Do something every 0.2 seconds
}

But why do it this way?

Why not just reset the timer to zero?

Subtracting the time interval from the elapsed time accounts for any excess time that may have passed since the timer became larger than the required delay.

This works because, when the timer becomes due, it’s almost always going to be the case that the amount of time that passed during the frame was more than the amount required to reach the interval duration.

Visualisation of triggering a function at fixed intervals using the subtraction method.

Resetting the timer to Zero disregards excess time that may have elapsed between reaching the interval time and actually resetting it.

Subtracting the delay from the time elapsed saves this extra time, keeping the interval duration as accurate as possible.

While simply resetting the timer to zero can cause the timer to be triggered a frame later than it would have done, as excess time, that has already passed, is written off and ignored, causing an inconsistent stuttering effect between the intervals.

For long durations, this isn’t noticeable at all, as the timer will only be out by a single frame each time, if it’s out of time at all.

However, for short, rapidly triggered functions, the effect can be much more noticeable, particularly if you’re triggering a sound effect that’s supposed to fire at fixed intervals.

How to create global time events with a Master Clock script

If you want multiple different scripts to respond to the same timing events then a good general approach is to manage time in one place, and then have other scripts respond to that script as required.

For example, if you want other scripts to respond to time that’s running out, or if you want to create a kind of day / night cycle, where things happen in your game at particular times, then it doesn’t make sense for each script to be measuring time in isolation.

Instead, you could use a simple Master Clock script to measure time and raise public Events whenever something needs to happen.

Like this:

using UnityEngine;
using System;
public class MasterClock : MonoBehaviour
{
    float totalTime;
    int secondsPassed;
    int minutesPassed;
    public static event Action onSecondPassed;
    public static event Action onMinutePassed;
    void Update()
    {
        totalTime += Time.deltaTime;
        int secondsNow = Mathf.FloorToInt(totalTime);
        int minutesNow = Mathf.FloorToInt(totalTime / 60);
        if (secondsNow > secondsPassed)
        {
            onSecondPassed?.Invoke();
            secondsPassed = secondsNow;
        }
        if (minutesNow > minutesPassed)
        {
            onMinutePassed?.Invoke();
            minutesPassed = minutesNow;
        }
    }
}

Importantly, this script only tracks one time value, interpreting it differently to achieve different interval durations, avoiding the possibility that multiple, independent, timers could fall out of sync with each other.

The subtraction method allows you to create relatively accurate timed intervals using a manual timer.

However, it’s also possible to trigger functions repeatedly, without measuring time yourself, by using Invoke Repeating.

How to trigger a function regularly (using Invoke Repeating)

Invoke Repeating works in the same way as Invoke, which uses a String to identify a function by name, and a Float to specify how long to wait before triggering it.

The difference is that Invoke Repeating will then, after the initial delay, repeat the function at a set interval.

Like this:

void Start()
{
    // Wait for 3 seconds then trigger My Function every 0.5 seconds.
    InvokeRepeating("MyFunction", 3, 0.5f);
}
void MyFunction()
{
    // Do something!
}

Invoke Repeating is as accurate as the time subtraction method, meaning that if you want to repeat the same function at regular intervals, both methods will work as well as each other.

However, the drawback is, that, just like when using Invoke, because it’s called using a string, you won’t be able to pass in any parameters when you use it.

Now it’s your turn

Now I want to hear from you.

How are you delaying the execution of logic in your game?

Are you using Invoke? Or are you measuring time manually?

And what have you learned about staging logic in Unity that you know other people will find helpful?

Whatever it is, let me know by leaving a comment.

by John Leonard French

Game audio professional and a keen amateur developer.

Get Game Development Tips, Straight to Your inbox

Get helpful tips & tricks and master game development basics the easy way, with deep-dive tutorials and guides.

My favourite time-saving Unity assets

Rewired (the best input management system)

Rewired is an input management asset that extends Unity's default input system, the Input Manager, adding much needed improvements and support for modern devices. Put simply, it's much more advanced than the default Input Manager and more reliable than Unity's new Input System. When I tested both systems, I found Rewired to be surprisingly easy to use and fully featured, so I can understand why everyone loves it.

DOTween Pro (should be built into Unity)

An asset so useful, it should already be built into Unity. Except it's not. DOTween Pro is an animation and timing tool that allows you to animate anything in Unity. You can move, fade, scale, rotate without writing Coroutines or Lerp functions.

Easy Save (there's no reason not to use it)

Easy Save makes managing game saves and file serialization extremely easy in Unity. So much so that, for the time it would take to build a save system, vs the cost of buying Easy Save, I don't recommend making your own save system since Easy Save already exists.

Image Attribution

Comments

  1. Just a tip.

    Use the nameof function to get the string name of the method you want to pass into Invoke/InvokeRepeating. This prevents issues with renaming and misspelling as well as removing the warning of a method being unused.

  2. I use each of these options, but mostly a simple script, though I don’t use Time.deltaTime, only Time.time. I’d love to try the first one.

    As for the coroutine, it’s a good idea to declare WaitForSeconds/WaitUntil etc. as a regular variable and with a separate variable for the amount of time. Something like
    float time;
    WaitForSeconds myTimer = new WaitForSeconds(time);
    and then in Coroutine:
    yield return myTimer;

    Normally, each coroutine launch forces a new WaitForSeconds declaration. If declared beforehand, it will only read the value.

    1. Author

      Thanks for the tip, declaring it in advance avoids creating garbage too! Since WaitForSeconds is a class.

  3. There’s one thing I don’t understand.

    In my opinion, despite Coroutines do create a small amount of Garbage , using Coroutines is still more efficient and concise than using update.

    Cause If you use Update,Unity will call it in every frame.
    And u alloc some new variables(timer,delay),they will also be recycled by GarbageCollector.

    Isn’t that so?

    1. Author

      I guess it depends on the type of variable. new reference variables in functions are stored on the heap, so they can create garbage, but value-type variables are stored on the stack, so they don’t. If you declared a new class in Update, then it’d cause garbage every frame, however I believe in a coroutine, so long as it wasn’t inside the part of coroutine that gets suspended, such as a while loop, then it may not do. However, this isn’t something that I’ve specifically tested. Personally, I don’t think there’s a lot of difference in performance, since the part of the coroutine that yields is just a different event function, like Update, so it still gets called every frame, it’s just easier to stop calling it when you’re finished with it. Hope that helps.

Leave a Comment