Posted On: 2025-02-03
If you've worked with the async/await pattern in C#, it may come as a surprise that Godot's ToSignal method - which gives C# the ability to await Godot's built-in signals - does not return a Task. This is a bit of a deviation from the norms of C# - most documentation and tutorials are written with Tasks in mind, and most libraries are built to leverage their ubiquity. Indeed, even though the documentation for using ToSignal specifically calls out that await in C# is "commonly used with operands of the type Task[...]", the actual implementation uses a custom awaiter.
For the most part this is invisible - the syntax to await a signal is no different from awaiting a Task - but it can become a bit of a problem when trying to combine multiple awaiters together. The static methods on the Task class - such as Task.WhenAll or Task.WhenAny are handy tools for recomposing multiple awaitables into a single awaitable Task. Unsurprisingly, the static Task methods only work with Task parameters, not custom awaiters, so it's not possible to (for example) use Task.WaitAll with multiple animations in order to wait for them all to complete.
Fortunately, there are ways to work around this problem - the simplest of which is to wrap up the custom awaiter in a new Task.
For my own code, I've approached this by leveraging async lambdas to succinctly build an IEnumerable
//firstAnimation and secondAnimation are simple code-based animations created using Godot's Tween class.
var awaiters = new List<SignalAwaiter> { ToSignal(firstAnimation, Tween.SignalName.Finished), ToSignal(secondAnimation, Tween.SignalName.Finished) };
var tasks = awaiters.Select(async x => await x);
await Task.WhenAll(tasks);
//At this point in the code, both animations have played to completion.
While this may seem like a trivially simple solution, documentation of (and online discussion about) custom awaiters is quite sparse, so I thought this would be a good addition to that (lean) corpus of information. As always, if you have any thoughts or feedback, please let me know.