#bevy #async #game-state #gamedev #resources #game #debugging

bevy_async_system

Provides the ability to wait for game status asynchronously

2 releases

0.1.1 Oct 16, 2023
0.1.0 Oct 15, 2023

#1704 in Asynchronous

MIT/Apache

245KB
1K SLoC

bevy_async_system

Crates.io MIT/Apache 2.0 Crates.io

This crate provides UniTask-like functionality to asynchronously await game state.

Usage

All examples are here.

once

The once is used to run the system only once.

In addition to simple system execution, it is also used to change state and send events.

use bevy::prelude::*;
use bevy_async_system::prelude::*;

#[derive(Eq, PartialEq, Copy, Clone, Debug, Default, States, Hash)]
enum ExampleState {
    #[default]
    First,
    Second,
}

#[derive(Resource, Eq, PartialEq, Default, Clone, Debug)]
struct Count(usize);

#[derive(Eq, PartialEq, Default, Clone, Debug)]
struct NonSendCount(usize);

fn setup(mut commands: Commands) {
    commands.spawn_async(|schedules| async move {
        schedules.add_system(Update, once::run(println_system)).await;
        schedules.add_system(Update, once::set_state(ExampleState::Second)).await;
        schedules.add_system(Update, once::init_resource::<Count>()).await;
        schedules.add_system(Update, once::init_non_send_resource::<NonSendCount>()).await;

        let count = schedules.add_system(Update, once::run(return_count)).await;
        schedules.add_system(Update, once::insert_resource(count)).await;
        schedules.add_system(Update, once::run(println_counts)).await;

        schedules.add_system(Update, once::send(AppExit)).await;
    });
}

fn println_system() {
    println!("hello!");
}


fn return_count() -> Count {
    Count(30)
}

fn println_counts(
    count: Res<Count>,
    non_send_count: NonSend<NonSendCount>
) {
    println!("{count:?}");
    println!("{non_send_count:?}");
}

wait

wait keeps the system running until a certain condition is met.

For example, you can easily write a process that waits until music playback ends, as shown below.

use bevy::prelude::*;
use bevy_async_system::prelude::*;

fn setup_async_systems(mut commands: Commands) {
    commands.spawn_async(|schedules| async move {
        schedules.add_system(Update, once::run(play_audio)).await;
        schedules.add_system(Update, wait::until(finished_audio)).await;
        info!("***** Finished audio *****");
        schedules.add_system(Update, once::send(AppExit)).await;
    });
}

fn play_audio(
    mut commands: Commands,
    asset_server: Res<AssetServer>,
) {
    commands.spawn(AudioBundle {
        source: asset_server.load("audio/higurashi.ogg"),
        settings: PlaybackSettings::ONCE,
    });
}

fn finished_audio(
    mut commands: Commands,
    audio: Query<(Entity, &AudioSink)>,
) -> bool {
    let Ok((entity, audio)) = audio.get_single() else { return false; };
    if audio.empty() {
        commands.entity(entity).despawn();
        true
    } else {
        false
    }
}

delay

You can delay the task using Frames or Timer.

use bevy::prelude::*;
use bevy_async_system::prelude::*;

fn setup(
    mut commands: Commands,
    mut settings: ResMut<FramepaceSettings>,
) {
    settings.limiter = Limiter::from_framerate(30.);
    commands.spawn_async(|schedules| async move {
        println!("Wait 3 seconds...");
        schedules.add_system(Update, delay::timer(Duration::from_secs(3))).await;

        println!("Wait 90 frames...");
        schedules.add_system(Update, delay::frames(90)).await;
    });
}

repeat

The repeat is used to run the system multiple times.

use bevy::prelude::*;
use bevy_async_system::prelude::*;

fn setup(mut commands: Commands) {
    commands.spawn_async(|schedules| async move {
        schedules.add_system(Update, repeat::times(5, count_up)).await;

        let handle = schedules.add_system(Update, repeat::forever(count_up));
        schedules.add_system(Update, delay::timer(Duration::from_secs(3))).await;

        // task and system cancel.
        drop(handle);

        println!("task canceled. Exit the application after 3 seconds.");
        // Delay to make sure the system does not run.
        schedules.add_system(Update, delay::timer(Duration::from_secs(3))).await;
        println!("App exit");
        schedules.add_system(Update, once::app_exit()).await;
    });
}

fn count_up(mut count: Local<u32>) {
    *count += 1;
    println!("count = {}", *count);
}

Compatible Bevy versions

bevy_async_system bevy
0.1 0.11

Dependencies

~24–34MB
~536K SLoC