top of page
Search
  • alexlpc2015

[Unity Coding Designs] #02 - Delayed Function Calls

Updated: Aug 10, 2022

Hi and welcome to my Unity Coding Designs Series!

This is a comprehensive series about various coding designs in unity. Some of the scripts are included in my unity utility plugin SKCell. I hope you will find this helpful!


Coding Designs #02 - Delayed Function Calls


Often we would like to call a function after a certain amount of time. Unity has an Invoke() method in MonoBehaviour, but it is very limited (only accepts method names; cannot pass in parameters to the method, etc.)

Today, we are going to write our own Invoke functions that will make your development journey much easier.

First, create a static utility class to hold the methods.

public static class CommonUtils
{

}

We need time, action, repeatCount, repeatInterval, and string id parameters for this invoke action method.

It should work as follows: Invoke an action after time seconds, then repeatedly every repeatInterval seconds, stopping at repeatCount times.

public static void InvokeAction(float seconds, Action callback, int repeatCount = 0, float repeatInterval = 1, string id = "")
{
    if (callback == null)
    {
        EditorLogError("InvokeAction: <Action callback> is null.");
        return;
    }

    SKCommonTimer.instance.InvokeAction(seconds, callback, repeatCount, repeatInterval, id);
}

This is the method from SKCell which puts the actual implementation inside the SKCommonTimer class. Let's take a look at that.

public sealed class SKCommonTimer : MonoSingleton<SKCommonTimer>
{
		//...

    public void InvokeAction(float seconds, Action callback, int          repeatCount=0, float repeatInterval=1, string id="")
    {
       Coroutine cr= StartCoroutine(SimpleActionCoroutine(seconds, callback, repeatCount, repeatInterval));
        if (id.Length > 0)
        {
            CommonUtils.InsertOrUpdateKeyValueInDictionary(crDict, id, cr);
        }
    }
}

I first started a unity coroutine called SimpleActionCoroutine. It's very simple as its name suggests:)

private IEnumerator SimpleActionCoroutine(float seconds, Action callback, int repeatCount = 0, float repeatInterval = 1, bool unlimited =false)
{
    yield return new WaitForSeconds(seconds);
    callback.Invoke();
    for (int i = 0; i < repeatCount; i++)
    {
        if (unlimited)
            i = 0;
        yield return new WaitForSeconds(repeatInterval);
        callback.Invoke();
    }
}

Now the main function of invoking an action is achieved, we can make a CancelInvoke() method to stop an invoke action session.

public void CancelInvokeAction(string id)
{
    if (crDict.ContainsKey(id))
    {
        StopCoroutine(crDict[id]);
        crDict.Remove(id);
    }
}

Notice that the crDict (coroutine dictionary) is maintained by the InvokeAction method where the key value pair of (invoke action id, corresponding coroutine) is inserted or updated to the dictionary whenever the method is called. This way we can quickly query the dictionary for a certain ongoing coroutine and stop it when the CancelInvoke method is called.

Here is the implementation of the InsertOrUpdateKeyValueInDictionary method.

public static void InsertOrUpdateKeyValueInDictionary<TKey, TValue>(Dictionary<TKey, TValue> dict, TKey key, TValue value)
{
    if (dict == null)
    {
        EditorLogError("InsertOrUpdateKeyInDictionary: <Dictionary dict> is null.");
        return;
    }
    if (dict.ContainsKey(key))
        dict[key] = value;
    else
        dict.Add(key, value);
}

We can now easily execute a delayed function call using these methods!

private int i = 10;
private string s = "Hello~";
private void Start()
{
    CommonUtils.InvokeAction(2.0f, () => i += 2);

    //Nested calls are OK!
    CommonUtils.InvokeAction(3.0f, ()=> 
        { 
            CommonUtils.InvokeAction(1.0f, () => s += i.ToString()); 
        }
     );
}

These are super useful in game development, remember to implement them on your own!



17 views0 comments

Recent Posts

See All
Post: Blog2_Post
bottom of page