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

bevy_async_system

提供异步等待游戏状态的能力

2个版本

0.1.1 2023年10月16日
0.1.0 2023年10月15日

#1583 in 异步

MIT/Apache

245KB
1K SLoC

bevy_async_system

Crates.io MIT/Apache 2.0 Crates.io

此crate提供类似于UniTask的功能,以异步等待游戏状态。

用法

所有示例均在此

once

once用于仅运行系统一次。

除了简单的系统执行外,还用于更改状态和发送事件。

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使系统在满足特定条件之前保持运行。

例如,您可以轻松编写一个等待音乐播放结束的过程,如下所示。

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

您可以使用帧或定时器延迟任务。

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

repeat用于多次运行系统。

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);
}

兼容的Bevy版本

bevy_async_system bevy
0.1 0.11

依赖项

~21–31MB
~477K SLoC