Skip to content

Instantly share code, notes, and snippets.

@rob5300
Last active November 11, 2024 21:57
Show Gist options
  • Save rob5300/5b449ee3c35795d2b8dc10261e285f7c to your computer and use it in GitHub Desktop.
Save rob5300/5b449ee3c35795d2b8dc10261e285f7c to your computer and use it in GitHub Desktop.
An example on using a Cancellation Token from a CancellationTokenSource to stop an async function in Unity. Uses UniTask.
using Cysharp.Threading.Tasks;
using System;
using System.Threading;
using UnityEngine;
public class UniTaskDemo_CancellationToken : MonoBehaviour
{
CancellationTokenSource animateTokenSource;
void Start()
{
//Start our example!
AnimateExample().Forget();
}
/// <summary>
/// Animate to a destination position. Existing animations are cancelled
/// </summary>
public async UniTask Animate(Vector3 destination, float duration)
{
CancelAnimation();
//Create new cancellation token source, linked to the lifetime of this monobehaviour
//Our token will get cancelled when the destroy token is cancelled
//NOTE: If this is not done the function will keep going until it throws an error!
// checking if this == null can be used as an alternative
#if UNITY_2022_2_OR_NEWER
animateTokenSource = CancellationTokenSource.CreateLinkedTokenSource(destroyCancellationToken);
#else
//Alternative to get a cancellation token that is cancelled on destroy in older unity versions (helper function from UniTask)
animateTokenSource = CancellationTokenSource.CreateLinkedTokenSource(this.GetCancellationTokenOnDestroy());
#endif
//Get a cancellation token that we can check during the lifetime of this async function call
//Check cancellation using the token as this is always linked to the source it came originally.
var token = animateTokenSource.Token;
float lerp = 0f;
Vector3 startPos = transform.position;
while(lerp < 0f && token.IsCancellationRequested)
{
lerp += Time.deltaTime / duration;
transform.position = Vector3.Lerp(startPos, destination, lerp);
//await next frame (note the token argument for this to be cancelled early!)
await UniTask.Yield(token);
}
if(!token.IsCancellationRequested)
{
transform.position = destination;
Debug.Log($"Successfully animated to '{destination}'", this);
}
}
public async UniTaskVoid AnimateExample()
{
await Animate(new Vector3(10f, 10f, 10f), 1f);
//If this monobehaviour was destroyed, return and stop!
if(this == null) return;
//Animate but do not await...
Animate(new Vector3(0f, 0f, 0f), 5f).Forget();
//This will cancel the above animation call as we did not await it!
//Calling animate again cancels the token
await Animate(new Vector3(5f, 5f, 5f), 5f);
}
/// <summary>
/// Cancel an existing animation
/// </summary>
public void CancelAnimation()
{
if(animateTokenSource != null)
{
animateTokenSource.Cancel();
animateTokenSource.Dispose();
animateTokenSource = null;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment