Skip to main content

spawn

Function spawn 

pub fn spawn(future: impl Future<Output = ()> + 'static) -> TaskHandle
Expand description

Create a new async background task.

This function allows creating a new async task in which Godot signals can be awaited, like it is possible in GDScript. If a reference to Self is not flexible enough regarding lifetimes, your function calling spawn() can capture the state in a Gd<Self> pointer instead. The TaskHandle that is returned provides synchronous introspection into the current state of the task.

Signals can be converted to futures in the following ways:

Signal typeSimple futureFallible future (handles freed object)
UntypedSignal::to_future()Signal::to_fallible_future()
TypedTypedSignal::to_future()TypedSignal::to_fallible_future()

§Panics

If called from any other thread than the main thread.

§Examples

An example using timers:

#[derive(GodotClass)]
#[class(init, base=Node)]
struct Game {
   base: Base<Node>,
}

#[godot_api]
impl INode for Game {
    fn ready(&mut self) {
        // Use `connect_other_gd` so that `Self::show_messages` receives a
        // `Gd<Self>` pointer instead of `&mut Self` reference.
        self.base()
            .get_node_as::<Node2D>("Player")
            .signals()
            .ready()
            .builder()
            .connect_other_gd(self, Self::show_messages);
    }
}

#[godot_api]
impl Game {
    // Async function that implements sleep using Godot timers.
    async fn sleep(&self, duration: f64) {
        # let timer = self.base().get_tree().create_timer(duration);
        // Use a future to wait for the timeout signal.
        # timer.signals().timeout().to_future().await;
    }

    // `#[func(gd_self)]`: receive `Gd<Self>` instead of `&mut Self`.
    #[func(gd_self)]
    fn show_messages(this: Gd<Self>) {
        // `spawn()` will capture the `this` variable -- this can't be done with
        // `&mut self` due to lifetimes.
        godot::task::spawn(async move {
            godot_print!("Start!");
            this.bind().sleep(1.0).await;
            godot_print!("One second later!")
        });
    }
}

With typed signals:

#[derive(GodotClass)]
#[class(init)]
struct Building {
   base: Base<RefCounted>,
}

#[godot_api]
impl Building {
   #[signal]
   fn constructed(seconds: u32);
}

let house = Building::new_gd();
godot::task::spawn(async move {
    println!("Wait for construction...");

    // Emitted arguments can be fetched in tuple form.
    // If the signal has no parameters, you can skip `let` and just await the future.
    let (seconds,) = house.signals().constructed().to_future().await;

    println!("Construction complete after {seconds}s.");
});

With untyped signals:

let node = Node::new_alloc();
let signal = Signal::from_object_signal(&node, "signal");

godot::task::spawn(async move {
    println!("Starting task...");

    // Explicit generic arguments needed, here `()`:
    signal.to_future::<()>().await;

    println!("Node has changed: {}", node.get_name());
});