Как читать события Беви, не поглощая их?

В настоящее время я пытаюсь использовать события, чтобы сигнализировать, когда персонаж прыгает в моей игре Bevy. Я хочу, чтобы система, обрабатывающая ввод игроков, отправлялаJumpedEvent которые затем могут быть получены другими системами для выполнения соответствующих действий (установки правильной анимации игрока, скорости, звука и т. д.), но первая система, прочитавшая событие, потребляет его.

Предоставляет ли Беви способ читать события, не просматривая их?

Вот мой текущий код:

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

2 ответа

Я просто понял, что делаю не так. Я использовал один глобальный ресурсEventReader слушать JumpedEventотправляемые экземпляры. КаждыйEventReaderчитает каждое событие только один раз. Вместо этого мне нужно было найти человекаEventReaderдля каждой системы, которая должна была прослушивать событие. Я сделал это с помощьюLocal EventReaders для каждой системы, которая должна была прослушивать событие. См. Измененный код ниже:

// 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 читатель.

Для потомков: теперь это значение по умолчанию для Беви.

Другие вопросы по тегам