UniTask based Debounce Method Help

Hi there,

Im new to UniTask and need help writing the right code for a debounce method

In my code im using bool but ideally i want to have a “void” if possible but i dont know.

Please advise

 public async UniTaskVoid DebounceMethod()
        {
            if (taskCompletionSource != null)
            {
                taskCompletionSource.TrySetCanceled();
                taskCompletionSource = null;
            }

           
            taskCompletionSource = AutoResetUniTaskCompletionSource<bool>.Create();

            await UniTask.WaitForSeconds(delayInSeconds);
      
            taskCompletionSource.TrySetResult(true);

            taskCompletionSource = null;
           
            onDefaultEvent(this);
        }

What are you debouncing? Just set a float for whatever the debounce time is and count it down.

Cooldown timers, gun bullet intervals, shot spacing, rate of fire:

This is my implementation using UniTask

using Cysharp.Threading.Tasks;
using System;
using System.Threading;

public class Debouncer
{
    private readonly float debounceTime;
    private readonly Action action;
    private CancellationTokenSource cts;

    public Debouncer(float ms, Action action)
    {
        this.debounceTime = ms;
        this.action = action;
    }

    public void Call()
    {
        cts?.Cancel();
        cts = new CancellationTokenSource();
        DebounceCall(cts.Token).Forget();
    }

    private async UniTask DebounceCall(CancellationToken cancellationToken)
    {
        await UniTask.Delay(TimeSpan.FromMilliseconds(debounceTime), cancellationToken: cancellationToken);

        if (!cancellationToken.IsCancellationRequested)
        {
            action();
        }
    }
}

And how to use it

using UnityEngine;

public class UniTaskDebounceExample : MonoBehaviour
{
    private Debouncer debouncer;

    private void Start()
    {
        debouncer = new Debouncer(500, () => Debug.Log("Hello world!"));
    }

    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space)) 
        {
            debouncer.Call();
        }
    }
}

I am sure there are fancier and more performance approaches but at least this gets the job done

Nice one :+1:

I have just two little nitpicks:

There’s no need to handle cancellation a second time manually, if you’re already passing the token to UniTask.Delay:

private async UniTask DebounceCall(CancellationToken cancellationToken)
{
    await UniTask.Delay(debounceTime, cancellationToken: cancellationToken);
    action();
}

decounceTime could be a TimeSpan (or at least an int) so that it’s not so ambiguous whether it’s in seconds or milliseconds:

public Debouncer(int ms, Action action)
{
    debounceTime = TimeSpan.FromMilliseconds(ms);
    this.action = action;
}

Seeing float in Unity makes me think seconds, and it’s a weird conversion to make, when TimeSpan.FromMilliseconds only accepts a double.

1 Like