Last active
November 11, 2024 21:57
-
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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