事件

可参考的官方例子: [ecs_event][example::ecs_event].


通过事件,可以在系统之间发送数据! 让你的系统之间相互沟通!

要发送事件,使用 EventWriter<T>。要接收事件,使用 EventReader<T>

每个 reader 都独立地跟踪它所读取的事件,所以你可以处理来自多个系统的相同事件。

    struct LevelUpEvent(Entity);

    fn player_level_up(
        mut ev_levelup: EventWriter<LevelUpEvent>,
        query: Query<(Entity, &PlayerXp)>,
    ) {
        for (entity, xp) in query.iter() {
            if xp.0 > 1000 {
                ev_levelup.send(LevelUpEvent(entity));
            }
        }
    }

    fn debug_levelups(
        mut ev_levelup: EventReader<LevelUpEvent>,
    ) {
        for ev in ev_levelup.iter() {
            eprintln!("Entity {:?} leveled up!", ev.0);
        }
    }

你需要通过应用程序生成器添加你的自定义事件类型:

    fn main() {
        App::new()
            // ...
            .add_event::<LevelUpEvent>()
            .add_system(player_level_up)
            .add_system(debug_levelups)
            // ...
            .run();
    }

事件是你处理跳转类数据流的工具。由于事件可以从任何系统发送并被多个系统接收,因此它们的用途非常广泛。

可能的陷阱

小心帧延迟、帧滞后的问题,如果 Bevy 在发送系统之前运行接收系统,这样的问题可能会发生。接收系统只有在下一帧更新时才有机会接收事件。如果你需要确保事件被立即、在同一帧内处理,你可以使用显式系统排序

事件不会持久化。它们被存储直到下一帧的结束,之后就会丢弃。如果你的系统不是每一帧都处理事件,你可能会错过一些事件。

这种设计的好处是,你不必担心未处理的事件会造成过多的内存占用。

如果你不喜欢这样,你可以手动控制事件被清除的时间(风险是如果你忘记清除它们,就有可能会内存泄漏和内存浪费)。