手动清除事件

点击这里下载本页的完整例子代码文件。


事件队列需要定期清理,这样它就不会无限制地增长和浪费无限制的内存。

Bevy 的默认清理策略是在每一帧都清除事件,但有双重缓冲,所以前一帧中产生的事件保持可用。这意味着你只能在事件发送后的下一帧结束之前处理这些事件。

这个默认策略对每一帧运行都会检查事件的系统很有效,这也是典型的用法模式。

然而,如果你的系统不是每一帧都读取事件,它们就会错过一些事件。出现这种情况的一些常见情况是:

  • 在运行中途可能提前返回的系统,导致不是每次运行都读取事件
  • 当使用固定的时间步长
  • 只在特定状态下运行的系统,比如你的游戏有一个暂停状态
  • 当使用自定义执行条件来控制你的系统时

为了能够在这类情况下可靠地管理事件,你可能想要手动的控制事件在内存中保留的时间。

你可以用你自己的策略取代 Bevy 的默认清理策略。

要做到这一点,只需使用 .init_resource (而不是 .add_event)方法将你的事件类型(封装为 Events<T>)添加到应用程序构造器中。

(.add_event 实际上只是一个方便的方法,它初始化了资源并为默认的清理策略添加了 Bevy 的内置系统(事件类型泛型化))

然后你必须谨慎地清除事件。如果你不经常这样做,你的事件可能会堆积起来,浪费内存。

示例

我们可以为此创建泛型系统。实现自定义清理策略,然后根据需要多次将该系统添加到你的App中,用于你想使用自定义行为的每个事件类型。

use bevy::app::Events;

fn main() {
    App::new()
        .add_plugins(DefaultPlugins)

        // add the `Events<T>` resource manually
        // these events will not have automatic cleanup
        .init_resource::<Events<MySpecialEvent>>()

        // this is a regular event type with automatic cleanup
        .add_event::<MyRegularEvent>()

        // add the cleanup systems
        .add_system(my_event_manager::<MySpecialEvent>)
        .run();
}

/// Custom cleanup strategy for events
///
/// Generic to allow using for any custom event type
fn my_event_manager<T: 'static + Send + Sync>(
    mut events: ResMut<Events<T>>,
) {
    // TODO: implement your custom logic
    // for deciding when to clear the events

    // clear all events like this:
    events.clear();

    // or with double-buffering
    // (this is what Bevy's default strategy does)
    events.update();

    // or drain them, if you want to iterate,
    // to access the values:
    for event in events.drain() {
        // TODO: do something with each event
    }
}