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, marker::PhantomData,
}; };
// TODO: These docs need to be moved around and adjusted /// Supertrait for the observer based [`BroadcastEvent`] and [`EntityEvent`].
/// 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.
/// ///
/// Events must be thread-safe. /// 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( #[diagnostic::on_unimplemented(
message = "`{Self}` is not an `Event`", message = "`{Self}` is not an `Event`",
label = "invalid `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 {} pub trait BroadcastEvent: Event {}
/// An [`Event`] that can be targeted at specific entities. /// 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 /// like [`trigger_targets`](World::trigger_targets), causing any [`Observer`] watching the event
/// for those entities to run. /// 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 /// based on the [`EntityEvent::Traversal`] type associated with the event. This enables use cases
/// such as bubbling events to parent entities for UI purposes. /// 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.trigger_targets(Damage { amount: 10.0 }, armor_piece);
/// ``` /// ```
/// ///
/// [`World`]: crate::world::World
/// [`TriggerTargets`]: crate::observer::TriggerTargets /// [`TriggerTargets`]: crate::observer::TriggerTargets
/// [`Observer`]: crate::observer::Observer /// [`Observer`]: crate::observer::Observer
/// [`Events<E>`]: super::Events
/// [`EventReader`]: super::EventReader
/// [`EventWriter`]: super::EventWriter
#[diagnostic::on_unimplemented( #[diagnostic::on_unimplemented(
message = "`{Self}` is not an `EntityEvent`", message = "`{Self}` is not an `EntityEvent`",
label = "invalid `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 base;
mod collections; mod collections;
mod event_cursor; mod event_cursor;

View File

@ -22,11 +22,13 @@ use bevy_ecs::{
system::{Commands, Query}, 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`]. /// See also [`On`], [`SceneSpawner::instance_is_ready`].
/// ///
/// [`On`]: bevy_ecs::observer::On /// [`On`]: bevy_ecs::observer::On
/// [`Event`]: bevy_ecs::event::Event
#[derive(Clone, Copy, Debug, Eq, PartialEq, EntityEvent, Reflect)] #[derive(Clone, Copy, Debug, Eq, PartialEq, EntityEvent, Reflect)]
#[reflect(Debug, PartialEq, Clone)] #[reflect(Debug, PartialEq, Clone)]
pub struct SceneInstanceReady { 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. 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: 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. - 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`. - `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`.