#events #bevy #consume

bevy_consumable_event

一个用于向Bevy添加可消费事件的crate

4个版本 (破坏性)

0.4.0 2024年7月6日
0.3.0 2024年2月18日
0.2.0 2024年2月5日
0.1.0 2024年1月2日

#532 in 游戏开发

Download history 115/week @ 2024-07-01 20/week @ 2024-07-08 2/week @ 2024-07-22 15/week @ 2024-07-29

65 个月下载

MIT/Apache

23KB
323

bevy_consumable_event

一个用于向Bevy添加可消费事件的crate。

为什么?

Bevy中的事件非常强大。然而,它们有一个限制,那就是不能被消费。例如,如果你在UI上点击,理想情况下你只想让一个系统来处理那个点击。否则,点击一个UI元素也会点击其下的所有元素,使得“顺序”变得无关紧要。

用法

标准的用法是使用App::add_consumable_eventApp::add_persistent_consumable_event(通过ConsumableEventApp扩展特质)。这两个函数都允许你使用可消费事件,但它们决定了你何时可以读取和消费事件。

  • App::add_consumable_event:事件将在每一帧的开始时被清除。因此,只有同一帧内并在ConsumableEventWriter之后运行的系统才能读取事件。
  • App::add_persistent_consumable_event:事件不会被自动清除(除非已经消费的事件)。因此,事件将保持直到某个系统消费它们(或者你手动清除事件)。注意这意味着同一个系统可以多次读取同一个事件(因此它有多次消费事件的机会)。

为了消费一个事件,只需在从ConsumableEventReader读取的项上调用consume()即可。

use bevy::prelude::Event;
use bevy_consumable_event::ConsumableEventReader;

#[derive(Event)]
struct MyEvent;

fn consume_all_events(mut events: ConsumableEventReader<MyEvent>) {
  for mut event in events.read() {
    event.consume();
  }
}

此外,你可以修改从ConsumableEventReader读取的事件(这样后续的读取可以基于这些修改操作)。

虽然使用App::add_consumable_eventApp::add_persistent_consumable_event是使用可消费事件的规范方法,就像常规事件一样,这些只是方便的。你也可以直接与ConsumableEvents交互,并使用自定义清除策略,使用ConsumableEvents::clearConsumableEvents::clear_consumed

示例

use bevy::{app::{ScheduleRunnerPlugin, RunMode}, prelude::*};
use bevy_consumable_event::{
  ConsumableEventApp,
  ConsumableEventReader,
  ConsumableEventWriter,
};

fn main() {
  App::new()
    .add_plugins(ScheduleRunnerPlugin { run_mode: RunMode::Once })
    .add_consumable_event::<MyEvent>()
    .add_systems(Main, (
        write_events,
        consume_odds_and_add_ten_to_evens,
        assert_remaining_events,
      ).chain()
    )
    .run();
}

#[derive(Event)]
struct MyEvent {
  value: usize,
}

fn write_events(mut events: ConsumableEventWriter<MyEvent>) {
  for value in 0..10 {
    events.send(MyEvent { value });
  }
}

fn consume_odds_and_add_ten_to_evens(
  mut events: ConsumableEventReader<MyEvent>,
) {
  for mut event in events.read() {
    if event.value % 2 == 1 {
      event.consume();
    } else {
      event.value += 10;
    }
  }
}

fn assert_remaining_events(mut events: ConsumableEventReader<MyEvent>) {
  let values = events.read().map(|event| event.value).collect::<Vec<_>>();
  assert_eq!(values, [10, 12, 14, 16, 18]);
}

注意事项

事件和消耗性事件不是互斥的 - 可以将类型添加为普通事件和消耗性事件。消耗性事件完全不与普通事件交互,所以一切都会正常工作。这可能会有些令人困惑。

事件也有多种策略来 1) 防止系统重复读取事件,2) 防止系统遗漏事件。对于消耗性事件,希望这些解决方案是不必要的。如果你使用非持久性消耗性事件,那么不应该发生重复读取(除了FixedUpdate系统)。无论如何,这些都是额外消耗事件的机会。遗漏事件是可以的,因为假设事件在帧的末尾被消耗。如果你确实使用持久性消耗性事件,则预期会发生重复读取。遗漏读取也不是问题,因为事件不会被清除。

许可证

在以下任一许可证下:

任选其一。

贡献

欢迎贡献!

除非你明确表示,否则根据Apache-2.0许可证定义,你提交给作品的所有贡献都将双重许可,如上所述,不附加任何额外条款或条件。

依赖项

~11MB
~194K SLoC