#bevy #macro #gamedev #impl-block #game

bevy_ergo_plugin

使用宏使构建 bevy 插件更加便捷

4 个版本

0.2.1 2023 年 5 月 26 日
0.2.0 2023 年 5 月 25 日
0.1.1 2023 年 5 月 23 日
0.1.0 2023 年 5 月 23 日

过程宏 中排名第 618

每月下载量 37

MIT 许可证

18KB
162 行代码(不包括注释)

bevy_ergo_plugin

使用宏使构建 bevy 插件更加便捷(在我看来)。

Bevy 的 API 将添加系统的实现与定义分开。将系统的运行条件和其它系统参数与定义分开增加了一层额外的间接层,损害了可读性并增加了样板代码(.add_system
该包的目的就是用更便捷的 API 替换那个 API,使用属性宏作为系统参数的标记。

bevy_plugin 属性放在结构的 impl 块上,将这个结构转换为 Bevy 插件,并注册其相关函数作为系统。
如果你想在插件的 Plugin::build 中添加额外功能(如添加资源或注册组件),则 bevy_plugin 属性化 impl 块中任何名为 build 的相关函数的内容将被插入到生成的 Plugin::build 实现中。

其他宏是之前提到的用于系统定义的参数标记。
对于任何未由特定标记包含的参数,你可以使用 sysparam 标记来定义自定义行为。

系统上的多个参数标记会堆叠到一个 add_system 调用上,因此你可以添加多个运行条件,并按预期工作。
此包尚未经过彻底测试,因此可能存在我未知的一些奇怪的错误。

示例

改编自 https://github.com/bevyengine/bevy/blob/latest/examples/ecs/run_conditions.rs\

use bevy::prelude::*;
use bevy_ergo_plugin::*;

fn main() {
    println!();
    println!("For the first 2 seconds you will not be able to increment the counter");
    println!("Once that time has passed you can press space, enter, left mouse, right mouse or touch the screen to increment the counter");
    println!();

    App::new()
        .add_plugins(DefaultPlugins)
        .add_plugin(Game)
        .run();
}
#[derive(Resource, Default)]
pub struct InputCounter(usize);

pub struct Game;
#[bevy_plugin]
impl Game {
    #[run_if(resource_exists::<InputCounter>())]
    #[run_if(Game::has_user_input)]
    pub fn increment_input_counter(mut counter: ResMut<InputCounter>) {
        counter.0 += 1;
    }

    #[run_if(resource_exists::<InputCounter>().and_then(
        |counter: Res<InputCounter>| counter.is_changed() && !counter.is_added()
    ))]
    pub fn print_input_counter(counter: Res<InputCounter>) {
        println!("Input counter: {}", counter.0);
    }

    #[run_if(Game::time_passed(2.0))]
    #[run_if(not(Game::time_passed(2.5)))]
    pub fn print_time_message() {
        println!(
            "It has been more than 2 seconds since the program started and less than 2.5 seconds"
        );
    }

    #[do_not_add]
    pub fn has_user_input(
        keyboard_input: Res<Input<KeyCode>>,
        mouse_button_input: Res<Input<MouseButton>>,
        touch_input: Res<Touches>,
    ) -> bool {
        keyboard_input.just_pressed(KeyCode::Space)
            || keyboard_input.just_pressed(KeyCode::Return)
            || mouse_button_input.just_pressed(MouseButton::Left)
            || mouse_button_input.just_pressed(MouseButton::Right)
            || touch_input.any_just_pressed()
    }

    #[do_not_add]
    pub fn time_passed(t: f32) -> impl FnMut(Local<f32>, Res<Time>) -> bool {
        move |mut timer: Local<f32>, time: Res<Time>| {
            *timer += time.delta_seconds();
            *timer >= t
        }
    }

    pub fn build(&self, app: &mut App) {
        app.init_resource::<InputCounter>();
    }
}

依赖

~0.6–1.1MB
~25K SLoC