This commit is contained in:
Tim Blackbird 2025-07-17 14:56:28 +02:00
parent 1161216938
commit 15ffea3884
4 changed files with 83 additions and 84 deletions

View File

@ -11,84 +11,9 @@ use core::{
marker::PhantomData,
};
// TODO: These docs need to be moved around and adjusted
/// Something that "happens" and can be processed by app logic.
///
/// Events can be triggered on a [`World`] using a method like [`trigger`](World::trigger),
/// causing any global [`Observer`] watching that event to run. This allows for push-based
/// event handling where observers are immediately notified of events as they happen.
///
/// Additional event handling behavior can be enabled by implementing the [`EntityEvent`]
/// and [`BufferedEvent`] traits:
///
/// - [`EntityEvent`]s support targeting specific entities, triggering any observers watching those targets.
/// They are useful for entity-specific event handlers and can even be propagated from one entity to another.
/// - [`BufferedEvent`]s support a pull-based event handling system where events are written using an [`EventWriter`]
/// and read later using an [`EventReader`]. This is an alternative to observers that allows efficient batch processing
/// of events at fixed points in a schedule.
/// Supertrait for the observer based [`BroadcastEvent`] and [`EntityEvent`].
///
/// Events must be thread-safe.
///
/// # Usage
///
/// The [`Event`] trait can be derived:
///
/// ```
/// # use bevy_ecs::prelude::*;
/// #
/// #[derive(BroadcastEvent)]
/// struct Speak {
/// message: String,
/// }
/// ```
///
/// An [`Observer`] can then be added to listen for this event type:
///
/// ```
/// # use bevy_ecs::prelude::*;
/// #
/// # #[derive(BroadcastEvent)]
/// # struct Speak {
/// # message: String,
/// # }
/// #
/// # let mut world = World::new();
/// #
/// world.add_observer(|trigger: On<Speak>| {
/// println!("{}", trigger.message);
/// });
/// ```
///
/// The event can be triggered on the [`World`] using the [`trigger`](World::trigger) method:
///
/// ```
/// # use bevy_ecs::prelude::*;
/// #
/// # #[derive(BroadcastEvent)]
/// # struct Speak {
/// # message: String,
/// # }
/// #
/// # let mut world = World::new();
/// #
/// # world.add_observer(|trigger: On<Speak>| {
/// # println!("{}", trigger.message);
/// # });
/// #
/// # world.flush();
/// #
/// world.trigger(Speak {
/// message: "Hello!".to_string(),
/// });
/// ```
///
/// For events that additionally need entity targeting or buffering, consider also deriving
/// [`EntityEvent`] or [`BufferedEvent`], respectively.
///
/// [`World`]: crate::world::World
/// [`Observer`]: crate::observer::Observer
/// [`EventReader`]: super::EventReader
/// [`EventWriter`]: super::EventWriter
#[diagnostic::on_unimplemented(
message = "`{Self}` is not an `Event`",
label = "invalid `Event`",
@ -129,7 +54,62 @@ pub trait Event: Send + Sync + 'static {
}
}
/// A global [`Event`] without an entity target.
/// An [`Event`] without an entity target.
///
/// [`BroadcastEvent`]s can be triggered on a [`World`] with the method [`trigger`](World::trigger),
/// causing any [`Observer`] watching the event for those entities to run.
///
/// # Usage
///
/// The [`BroadcastEvent`] trait can be derived:
///
/// ```
/// # use bevy_ecs::prelude::*;
/// #
/// #[derive(BroadcastEvent)]
/// struct Speak {
/// message: String,
/// }
/// ```
///
/// An [`Observer`] can then be added to listen for this event type:
///
/// ```
/// # use bevy_ecs::prelude::*;
/// #
/// # #[derive(BroadcastEvent)]
/// # struct Speak {
/// # message: String,
/// # }
/// #
/// # let mut world = World::new();
/// #
/// world.add_observer(|trigger: On<Speak>| {
/// println!("{}", trigger.message);
/// });
/// ```
///
/// The event can be triggered on the [`World`] using the [`trigger`](World::trigger) method:
///
/// ```
/// # use bevy_ecs::prelude::*;
/// #
/// # #[derive(BroadcastEvent)]
/// # struct Speak {
/// # message: String,
/// # }
/// #
/// # let mut world = World::new();
/// #
/// world.trigger(Speak {
/// message: "Hello!".to_string(),
/// });
/// ```
///
/// For events that additionally need entity targeting or buffering, consider also deriving
/// [`EntityEvent`] or [`BufferedEvent`], respectively.
///
/// [`Observer`]: crate::observer::Observer
pub trait BroadcastEvent: Event {}
/// An [`Event`] that can be targeted at specific entities.
@ -138,7 +118,7 @@ pub trait BroadcastEvent: Event {}
/// like [`trigger_targets`](World::trigger_targets), causing any [`Observer`] watching the event
/// for those entities to run.
///
/// Unlike basic [`Event`]s, entity events can optionally be propagated from one entity target to another
/// Unlike [`BroadcastEvent`]s, entity events can optionally be propagated from one entity target to another
/// based on the [`EntityEvent::Traversal`] type associated with the event. This enables use cases
/// such as bubbling events to parent entities for UI purposes.
///
@ -237,12 +217,8 @@ pub trait BroadcastEvent: Event {}
/// world.trigger_targets(Damage { amount: 10.0 }, armor_piece);
/// ```
///
/// [`World`]: crate::world::World
/// [`TriggerTargets`]: crate::observer::TriggerTargets
/// [`Observer`]: crate::observer::Observer
/// [`Events<E>`]: super::Events
/// [`EventReader`]: super::EventReader
/// [`EventWriter`]: super::EventWriter
#[diagnostic::on_unimplemented(
message = "`{Self}` is not an `EntityEvent`",
label = "invalid `EntityEvent`",

View File

@ -1,4 +1,24 @@
//! Event handling types.
//! Events are that "happens" and can be processed by app logic.
//!
//! [Event]s can be triggered on a [`World`](bevy_ecs::world::World) using a method like [`trigger`],
//! causing any global [`Observer`] watching that event to run. This allows for push-based
//! event handling where observers are immediately notified of events as they happen.
//!
//! Event handling behavior can be enabled by implementing the [`EntityEvent`]
//! and [`BufferedEvent`] traits:
//!
//! - [`Event`]: A supertrait for observer events.
//! - [`BroadcastEvent`]: An observer event without an entity target.
//! - [`EntityEvent`]s support targeting specific entities, triggering any observers watching those targets.
//! They are useful for entity-specific event handlers and can even be propagated from one entity to another.
//! - [`BufferedEvent`]s support a pull-based event handling system where events are written using an [`EventWriter`]
//! and read later using an [`EventReader`]. This is an alternative to observers that allows efficient batch processing
//! of events at fixed points in a schedule.
//!
//! [`World`]: crate::world::World
//! [`trigger`]: crate::world::World::trigger
//! [`Observer`]: crate::observer::Observer
mod base;
mod collections;
mod event_cursor;

View File

@ -22,11 +22,13 @@ use bevy_ecs::{
system::{Commands, Query},
};
/// Triggered on a scene's parent entity when [`crate::SceneInstance`] becomes ready to use.
/// This [`Event`] is triggered when the [`SceneInstance`] becomes ready to use.
/// If the scene has a parent the event will be triggered on that entity, otherwise the event has no target.
///
/// See also [`On`], [`SceneSpawner::instance_is_ready`].
///
/// [`On`]: bevy_ecs::observer::On
/// [`Event`]: bevy_ecs::event::Event
#[derive(Clone, Copy, Debug, Eq, PartialEq, EntityEvent, Reflect)]
#[reflect(Debug, PartialEq, Clone)]
pub struct SceneInstanceReady {

View File

@ -24,6 +24,7 @@ All three patterns are fundamentally different in both the interface and usage.
APIs are typically built to support only one of them.
This has led to a lot of confusion and frustration for users. Common footguns include:
- Using a "buffered event" with an observer, or an observer event with `EventReader`, leaving the user wondering why the event is not being detected.
- `On`(formerly `Trigger`) has a `target` getter which would cause confusion for events only mean to be used with `trigger` where it returns `Entity::PLACEHOLDER`.