rust - 如何在不消耗 Bevy 事件的情况下读取它们?
问题描述
我目前正在尝试使用事件来表示角色何时在我的 Bevy 游戏中跳跃。我希望处理玩家输入的系统发送一个JumpedEvent
然后其他系统可以接收它以执行适当的操作(设置正确的玩家动画、速度、声音等),但第一个读取事件的系统会消耗它。
Bevy 是否提供了一种无需消费即可读取事件的方法?
这是我当前的代码:
// Sends a JumpedEvent when the jump key is pressed
fn player_jump_event_system(
keyboard_input: Res<Input<KeyCode>>,
mut jump_events: ResMut<Events<JumpedEvent>>,
mut query: Query<(&Controlled, &mut Jumps)>,
) {
for (controlled, mut jumps) in &mut query.iter() {
if keyboard_input.just_pressed(controlled.jump)
&& jumps.jumps_remaining > 0
{
jumps.jumps_remaining -= 1;
jump_events.send(JumpedEvent {
jump_number: jumps.max_jumps - jumps.jumps_remaining,
});
}
}
}
// This system consumes the JumpedEvent that was sent
fn control_player_jump_system(
jump_events: ResMut<Events<JumpedEvent>>,
mut jump_event_listener: ResMut<JumpedEventListener>,
mut query: Query<(&Controlled, &mut Jumps, &mut Velocity)>,
) {
const PLAYER_JUMP_SPEED: f32 = 450.0;
const MULTI_JUMP_MODIFIER: f32 = 0.9;
// For every jump event, make player jump slightly less high
for jump_event in jump_event_listener.jumped_event_reader.iter(&jump_events)
{
for (_, _, mut velocity) in &mut query.iter() {
*velocity.0.y_mut() = PLAYER_JUMP_SPEED
* MULTI_JUMP_MODIFIER.powi(i32::from(jump_event.jump_number));
}
}
}
// This is the system that cannot receive the event because the above system consumes it
fn select_animation_system(
texture_atlases: Res<Assets<TextureAtlas>>,
jump_events: ResMut<Events<JumpedEvent>>,
mut jump_event_listener: ResMut<JumpedEventListener>,
mut query: Query<(
&Jumps,
&Velocity,
&AnimatedPlayer,
&mut TextureAtlasSprite,
&mut Handle<TextureAtlas>,
)>,
) {
for (_, velocity, animations, mut sprite, mut texture_atlas) in
&mut query.iter()
{
// Check if the player just jumped
let just_jumped = jump_event_listener
.jumped_event_reader
.iter(&jump_events)
.next()
.is_some();
// Omitting irrelevant details...
if just_jumped {
sprite.index = 0;
}
}
}
解决方案
我才意识到我做错了什么。我正在使用单个全局资源EventReader
来收听JumpedEvent
正在发送的实例。每个EventReader
只读取每个事件一次。相反,我需要做的是EventReader
为每个需要监听事件的系统配备一个人。我通过Local
EventReader
对需要监听事件的每个系统使用 s 来做到这一点。见下面修改后的代码:
// Sends a JumpedEvent when the jump key is pressed
fn player_jump_event_system(
keyboard_input: Res<Input<KeyCode>>,
mut jump_events: ResMut<Events<JumpedEvent>>,
mut query: Query<(&Controlled, &mut Jumps)>,
) {
for (controlled, mut jumps) in &mut query.iter() {
if keyboard_input.just_pressed(controlled.jump)
&& jumps.jumps_remaining > 0
{
jumps.jumps_remaining -= 1;
jump_events.send(JumpedEvent {
jump_number: jumps.max_jumps - jumps.jumps_remaining,
});
}
}
}
// This system consumes the JumpedEvent that was sent
fn control_player_jump_system(
jump_events: ResMut<Events<JumpedEvent>>,
// See that this line now specifies that the resource is local to the system
mut jump_event_listener: Local<JumpedEventListener>,
mut query: Query<(&Controlled, &mut Jumps, &mut Velocity)>,
) {
const PLAYER_JUMP_SPEED: f32 = 450.0;
const MULTI_JUMP_MODIFIER: f32 = 0.9;
// For every jump event, make player jump slightly less high
for jump_event in jump_event_listener.jumped_event_reader.iter(&jump_events)
{
for (_, _, mut velocity) in &mut query.iter() {
*velocity.0.y_mut() = PLAYER_JUMP_SPEED
* MULTI_JUMP_MODIFIER.powi(i32::from(jump_event.jump_number));
}
}
}
// This is the system that cannot receive the event because the above system consumes it
fn select_animation_system(
texture_atlases: Res<Assets<TextureAtlas>>,
jump_events: ResMut<Events<JumpedEvent>>,
// See that this line now specifies that the resource is local to the system
mut jump_event_listener: Local<JumpedEventListener>,
mut query: Query<(
&Jumps,
&Velocity,
&AnimatedPlayer,
&mut TextureAtlasSprite,
&mut Handle<TextureAtlas>,
)>,
) {
for (_, velocity, animations, mut sprite, mut texture_atlas) in
&mut query.iter()
{
// Check if the player just jumped
let just_jumped = jump_event_listener
.jumped_event_reader
.iter(&jump_events)
.next()
.is_some();
// Omitting irrelevant details...
if just_jumped {
sprite.index = 0;
}
}
}
因此,每个EventReader
人在阅读每个事件时都会消耗它。因此,要拥有多个消费系统,每个系统都需要一个Local
阅读器。
推荐阅读
- java - UIautomatorviewer.bat 中没有资源 ID 元素
- jquery - 外部加载的导航无法在移动设备上运行
- javascript - 如果进度条的值为 100,如何使按钮出现?
- android - Google-Fit Sensors API 未找到手表
- image - 如何将图像制作为切换按钮以在本机反应中显示两个不同的图像
- ibm-midrange - 如果没有程序更改,是否有任何方法可以处理“接收器太小而无法容纳结果”问题
- sql - SQL查询从多条记录中获取结果到一行
- typescript - TypeScript,详尽性检查无法正常工作
- reactjs - react.js 模块中的多个导出默认值
- java - 使用 `==` 比较字符串