Await All in Godot 4
Godot 4 introduced the await
keyword to pause function execution. It can be used with signals or other functions. Execution will resume when the signal is emitted or the function returns (Note that the function might contain its own await
calls).
func await_confirmation():
await $Button.pressed
$Modal.hide()
func await_modal_hide():
await await_confirmation()
# Do something after the modal is hidden
In various situations, I needed to pause function execution until several asynchronous conditions were satisfied. An example is waiting for a list of objects to finish animating, with each object having its unique animation duration and conditions.
Below is my solution to that problem:
# This needs to be added as an auto-load (I used the global name `Co`)
class_name Coroutines
extends Node
func await_all(list: Array):
var counter = {
value = list.size()
}
for el in list:
if el is Signal:
el.connect(count_down.bind(counter), CONNECT_ONE_SHOT)
elif el is Callable:
func_wrapper(el, count_down.bind(counter))
while counter.value > 0:
await get_tree().process_frame
func count_down(dict):
dict.value -= 1
func func_wrapper(call: Callable, call_back: Callable):
await call.call()
call_back.call()
# Usage example
func do_something():
await Co.await_all([obj1.animated, obj2.execute, obj3.pressed])
# Continue execution after all signals emit and functions return
This script must be added as an Autoload in Godot since it relies on the SceneTree.process_frame
signal. My attempts to implement the function without this requirement led to issues where func_wrapper
did not return as expected.
The await_all
function can accept a list containing either Signals or Callables. The function in the Callable will be immediately executed, and its return awaited.