#bevy #spawning #spawn

spew

Bevy中创建对象的一个简单助手

11个不稳定版本 (5个破坏性版本)

0.6.0 2024年7月4日
0.6.0-rc2024年6月11日
0.5.1 2024年2月18日
0.4.0 2024年1月21日
0.1.1 2023年3月19日

#83 in 游戏开发

Download history 70/week @ 2024-05-04 72/week @ 2024-05-11 84/week @ 2024-05-18 92/week @ 2024-05-25 82/week @ 2024-06-01 110/week @ 2024-06-08 89/week @ 2024-06-15 72/week @ 2024-06-22 120/week @ 2024-06-29 37/week @ 2024-07-06 56/week @ 2024-07-13 69/week @ 2024-07-20 119/week @ 2024-07-27 57/week @ 2024-08-03 66/week @ 2024-08-10 38/week @ 2024-08-17

293次每月下载
foxtrot 中使用

MIT/Apache

36KB
313

Spew

crates.io docs.rs

Bevy中创建对象的一个简单助手。

用法

首先,创建一个 enum 来持有你想要创建的对象

#[derive(Debug, Eq, PartialEq)]
enum Objects {
    Player,
    Monster,
    Coin,
}

考虑你想传递给创建函数的数据。在这个例子中,我们将为新的对象指定一个 Transform。接下来,将插件添加到你的应用中,注意我们刚才提到的两种类型

use spew::prelude::*;
use bevy::prelude::*;

fn main() {
    App::new()
    // ...
        .add_plugins(SpewPlugin::<Objects, Transform>::default()) // <--- Add the plugin
    // ...
        .run();
}

现在,我们准备注册我们的创建函数。每个 enum 的变体将与它自己的创建函数相关联,该函数接受一个 &mut World 和用户提供的参数

use spew::prelude::*;
use bevy::prelude::*;

fn main() {
    App::new()
    // ...
        .add_spawners( // <--- Register the spawn functions
            (Objects::Player, spawn_player),
            (Objects::Monster, spawn_monster),
            (Objects::Coin, spawn_coin),
        )
    // ...
        .run();
}

fn spawn_player(In(transform): In<Transform>, mut commands: Commands) {
    commands.spawn((
        Name::new("Spiffy the Adventurer"),
        TransformBundle::from_transform(transform),
    ));
}

fn spawn_monster(In(transform): In<Transform>, mut commands: Commands) {
    commands.spawn((
        Name::new("Grumblor the Grumpy"),
        TransformBundle::from_transform(transform),
    ));
}

fn spawn_coin(In(transform): In<Transform>, mut commands: Commands) {
    commands.spawn((
        Name::new("$1000"),
        TransformBundle::from_transform(transform),
    ));
}

最后,我们可以通过发送一个 SpawnEvent 来启动我们的创建函数

use spew::prelude::*;
use bevy::prelude::*;

fn main() {
    App::new()
    // ...
        .add_systems(Startup, setup_map)
    // ...
        .run();
}

fn setup_map(mut spawn_events: EventWriter<SpawnEvent<Object, Transform>>) {
    spawn_events.send(SpawnEvent::with_data(
        Objects::Player,
        Transform::from_xyz(0.0, 0.0, 0.0),
    ));
    spawn_events.send(SpawnEvent::with_data(
        Objects::Monster,
        Transform::from_xyz(5.0, 0.0, 0.0),
    ));
    spawn_events.send(SpawnEvent::with_data(
        Objects::Coin,
        Transform::from_xyz(10.0, 0.0, 0.0),
    ));
}

你可以阅读文档或浏览示例以获取更多用法。其他你可以做的事情包括延迟创建、根据帧数或时间创建,或将创建列表组织到多个枚举中。

兼容性

bevy spew
0.14 0.6
0.13 0.5
0.12 0.4
0.11 0.3
0.10 0.2

动机

Bevy的 Commands API 允许你使用任意组件创建新实体

use bevy::prelude::*;

fn spawn_player(commands: &mut Commands) {
    commands.spawn((
        Name::new("Adventurer"),
        TransformBundle::from_transform(Transform::from_xyz(0.0, 0.0, 0.0)),
    ));
}

这很好!我们可以通过添加更多的组件(如资产)来创建更复杂的对象

use std::f32::consts::TAU;
use bevy::prelude::*;

fn spawn_bullet(commands: &mut Commands, asset_server: Res<AssetServer>) {
    commands.spawn((
        Name::new("Bullet"),
        SceneBundle {
            scene: asset_server.load("models/bullet.gltf#Scene0"),
            transform: Transform {
                translation: Vec3::new(5.0, 4.0, 12.0),
                scale: Vec3::splat(0.012),
                rotation: Quat::from_rotation_y(TAU / 2.),
            },
            ..default()
        },
    ));
}

但在实际项目中,我们不会这样创建子弹。子弹将在某种平移下由武器创建。因此,我们可以这样封装子弹的创建

use bevy::prelude::*;
fn handle_input(...) {
    // ...
    if should_fire_bullet {
        let position = player_transform.translation;
        spawn_bullet(&mut commands, &asset_server, position);
    }
}

fn spawn_bullet(commands: &mut Commands, asset_server: &AssetServer, position: Vec3) {
    commands.spawn((
        Name::new("Bullet"),
        SceneBundle {
            scene: asset_server.load("models/bullet.gltf#Scene0"),
            transform: Transform {
                translation: position,
                scale: Vec3::splat(0.012),
                rotation: Quat::from_rotation_y(TAU / 2.),
            },
            ..default()
        },
    ));
}

如你所见,这可行,但看起来很糟糕。 handle_input 必须传递一个可能不需要的资产服务器,而 spawn_bullet 有很多看似无关的参数,这些参数会随着时间的推移而增长。参数列表的增长在编写系统时并不是问题,但请注意,这里的 spawn_bullet 已不再是系统,而是一个辅助函数。因此,其调用将随着时间的推移而变长、变丑,所有参数都会泄漏到 handle_input 中。

解决这个问题是将子弹的生成移动到一个独立的系统,该系统通过事件间接被 handle_input 访问,这正是这个库能帮助你实现的事情!:)

依赖关系

~22MB
~418K SLoC