11个不稳定版本 (5个破坏性版本)
0.6.0 | 2024年7月4日 |
---|---|
0.6.0-rc | 2024年6月11日 |
0.5.1 | 2024年2月18日 |
0.4.0 | 2024年1月21日 |
0.1.1 | 2023年3月19日 |
#83 in 游戏开发
293次每月下载
在 foxtrot 中使用
36KB
313 行
Spew
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