pub struct Observer { /* private fields */ }
Expand description
An Observer
system. Add this Component
to an Entity
to turn it into an “observer”.
Observers watch for a “trigger” of a specific Event
. An event can be triggered on the World
by calling World::trigger
. It can also be queued up as a Command
using Commands::trigger
.
When a World
triggers an Event
, it will immediately run every Observer
that watches for that Event
.
§Usage
The simplest usage of the observer pattern looks like this:
#[derive(Event)]
struct Speak {
message: String,
}
world.add_observer(|event: On<Speak>| {
println!("{}", event.message);
});
world.trigger(Speak {
message: "Hello!".into(),
});
Notice that we used World::add_observer
. This is just a shorthand for spawning an Entity
with an Observer
manually:
// These are functionally the same:
world.add_observer(|event: On<Speak>| {});
world.spawn(Observer::new(|event: On<Speak>| {}));
Observers are a specialized System
called an ObserverSystem
. The first parameter must be On
, which provides access
to the Event
, the Trigger
, and some additional execution context.
Because they are systems, they can access arbitrary World
data by adding SystemParam
s:
world.add_observer(|event: On<PrintNames>, names: Query<&Name>| {
for name in &names {
println!("{name:?}");
}
});
You can also add Commands
, which means you can spawn new entities, insert new components, etc:
world.add_observer(|event: On<SpawnThing>, mut commands: Commands| {
commands.spawn(Thing);
});
Observers can also trigger new events:
world.add_observer(|event: On<A>, mut commands: Commands| {
commands.trigger(B);
});
When the commands are flushed (including these “nested triggers”) they will be recursively evaluated until there are no commands left, meaning nested triggers all evaluate at the same time!
§Event Trigger
behavior
Each Event
defines a Trigger
behavior, which determines which observers will run for the given Event
and how they will be run.
Event
by default (when derived) uses GlobalTrigger
. When it is triggered any Observer
watching for it will be run.
§Event sub-types
There are some built-in specialized Event
types with custom Trigger
logic:
EntityEvent
/EntityTrigger
: AnEvent
that targets a specific entity. This also has opt-in support for “event bubbling” behavior. SeeEntityEvent
for details.EntityComponentsTrigger
: AnEvent
that targets an entity and one or more components on that entity. This is used for component lifecycle events.
You can also define your own!
§Observer execution timing
Observers triggered via World::trigger
are evaluated immediately, as are all commands they queue up.
Observers triggered via Commands::trigger
are evaluated at the next sync point in the ECS schedule, just like any other Command
.
To control the relative ordering of observer trigger commands sent from different systems, order the systems in the schedule relative to each other.
Currently, Bevy does not provide a way to specify the relative ordering of observers watching for the same event. Their ordering is considered to be arbitrary. It is recommended to make no assumptions about their execution order.
Commands sent by observers are currently not immediately applied. Instead, all queued observers will run, and then all of the commands from those observers will be applied.
§ObservedBy
When entities are observed, they will receive an ObservedBy
component,
which will be updated to track the observers that are currently observing them.
§Manual Observer
target configuration
You can manually control the targets that an observer is watching by calling builder methods like Observer::with_entity
before inserting the Observer
component.
In general, it is better to use the EntityWorldMut::observe
or EntityCommands::observe
methods,
which spawns a new observer, and configures it to watch the entity it is called on.
§Cleaning up observers
If an EntityEvent
Observer
targets specific entities, and all of those entities are despawned, the Observer
entity will also be despawned.
This protects against observer “garbage” building up over time.
§Component lifecycle events: Observers vs Hooks
It is important to note that observers, just like hooks, can watch for and respond to lifecycle events. Unlike hooks, observers are not treated as an “innate” part of component behavior: they can be added or removed at runtime, and multiple observers can be registered for the same lifecycle event for the same component.
The ordering of hooks versus observers differs based on the lifecycle event in question:
- when adding components, hooks are evaluated first, then observers
- when removing components, observers are evaluated first, then hooks
This allows hooks to act as constructors and destructors for components, as they always have the first and final say in the component’s lifecycle.
§Observer re-targeting
Currently, observers cannot be retargeted after spawning: despawn and respawn an observer as a workaround.
§Internal observer cache
For more efficient observer triggering, Observers make use of the internal CachedObservers
storage.
In general, this is an implementation detail developers don’t need to worry about, but it can be used when implementing custom Trigger
types, or to add “dynamic” observers for cases like scripting / modding.
Implementations§
Source§impl Observer
impl Observer
Sourcepub fn with_dynamic_runner(
runner: unsafe fn(DeferredWorld<'_>, Entity, &TriggerContext, PtrMut<'_>, PtrMut<'_>),
) -> Observer
pub fn with_dynamic_runner( runner: unsafe fn(DeferredWorld<'_>, Entity, &TriggerContext, PtrMut<'_>, PtrMut<'_>), ) -> Observer
Creates a new Observer
with custom runner, this is mostly used for dynamic event observers
Sourcepub fn with_entity(self, entity: Entity) -> Observer
pub fn with_entity(self, entity: Entity) -> Observer
Observes the given entity
(in addition to any entity already being observed).
This will cause the Observer
to run whenever an EntityEvent::event_target
is the given entity
.
Note that if this is called after an Observer
is spawned, it will produce no effects.
Sourcepub fn with_entities<I>(self, entities: I) -> Observerwhere
I: IntoIterator<Item = Entity>,
pub fn with_entities<I>(self, entities: I) -> Observerwhere
I: IntoIterator<Item = Entity>,
Observes the given entities
(in addition to any entity already being observed).
This will cause the Observer
to run whenever an EntityEvent::event_target
is any of the entities
.
Note that if this is called after an Observer
is spawned, it will produce no effects.
Sourcepub fn watch_entity(&mut self, entity: Entity)
pub fn watch_entity(&mut self, entity: Entity)
Observes the given entity
(in addition to any entity already being observed).
This will cause the Observer
to run whenever an EntityEvent::event_target
is the given entity
.
Note that if this is called after an Observer
is spawned, it will produce no effects.
Sourcepub fn watch_entities<I>(&mut self, entities: I)where
I: IntoIterator<Item = Entity>,
pub fn watch_entities<I>(&mut self, entities: I)where
I: IntoIterator<Item = Entity>,
Observes the given entity
(in addition to any entity already being observed).
This will cause the Observer
to run whenever an EntityEvent::event_target
is any of the entities
.
Note that if this is called after an Observer
is spawned, it will produce no effects.
Sourcepub fn with_component(self, component: ComponentId) -> Observer
pub fn with_component(self, component: ComponentId) -> Observer
Observes the given component
. This will cause the Observer
to run whenever the Event
has
an EntityComponentsTrigger
that targets the given component
.
Sourcepub unsafe fn with_event_key(self, event_key: EventKey) -> Observer
pub unsafe fn with_event_key(self, event_key: EventKey) -> Observer
Sourcepub fn with_error_handler(
self,
error_handler: fn(BevyError, ErrorContext),
) -> Observer
pub fn with_error_handler( self, error_handler: fn(BevyError, ErrorContext), ) -> Observer
Sets the error handler to use for this observer.
See the error
module-level documentation for more information.
Sourcepub fn descriptor(&self) -> &ObserverDescriptor
pub fn descriptor(&self) -> &ObserverDescriptor
Returns the ObserverDescriptor
for this Observer
.
Sourcepub fn system_name(&self) -> DebugName
pub fn system_name(&self) -> DebugName
Returns the name of the Observer
’s system .
Trait Implementations§
Source§impl Component for Observer
impl Component for Observer
Source§const STORAGE_TYPE: StorageType = StorageType::SparseSet
const STORAGE_TYPE: StorageType = StorageType::SparseSet
Source§type Mutability = Mutable
type Mutability = Mutable
Component<Mutability = Mutable>
,
while immutable components will instead have Component<Mutability = Immutable>
. Read moreSource§fn on_add() -> Option<for<'w> fn(DeferredWorld<'w>, HookContext)>
fn on_add() -> Option<for<'w> fn(DeferredWorld<'w>, HookContext)>
Source§fn on_remove() -> Option<for<'w> fn(DeferredWorld<'w>, HookContext)>
fn on_remove() -> Option<for<'w> fn(DeferredWorld<'w>, HookContext)>
Source§fn register_required_components(
_component_id: ComponentId,
required_components: &mut RequiredComponentsRegistrator<'_, '_>,
)
fn register_required_components( _component_id: ComponentId, required_components: &mut RequiredComponentsRegistrator<'_, '_>, )
Source§fn on_insert() -> Option<for<'w> fn(DeferredWorld<'w>, HookContext)>
fn on_insert() -> Option<for<'w> fn(DeferredWorld<'w>, HookContext)>
Source§fn on_replace() -> Option<for<'w> fn(DeferredWorld<'w>, HookContext)>
fn on_replace() -> Option<for<'w> fn(DeferredWorld<'w>, HookContext)>
Source§fn on_despawn() -> Option<for<'w> fn(DeferredWorld<'w>, HookContext)>
fn on_despawn() -> Option<for<'w> fn(DeferredWorld<'w>, HookContext)>
Source§fn clone_behavior() -> ComponentCloneBehavior
fn clone_behavior() -> ComponentCloneBehavior
Source§fn map_entities<E>(_this: &mut Self, _mapper: &mut E)where
E: EntityMapper,
fn map_entities<E>(_this: &mut Self, _mapper: &mut E)where
E: EntityMapper,
EntityMapper
. This is used to remap entities in contexts like scenes and entity cloning.
When deriving Component
, this is populated by annotating fields containing entities with #[entities]
Read moreAuto Trait Implementations§
impl Freeze for Observer
impl !RefUnwindSafe for Observer
impl Send for Observer
impl Sync for Observer
impl Unpin for Observer
impl !UnwindSafe for Observer
Blanket Implementations§
Source§impl<T, U> AsBindGroupShaderType<U> for T
impl<T, U> AsBindGroupShaderType<U> for T
Source§fn as_bind_group_shader_type(&self, _images: &RenderAssets<GpuImage>) -> U
fn as_bind_group_shader_type(&self, _images: &RenderAssets<GpuImage>) -> U
T
ShaderType
for self
. When used in AsBindGroup
derives, it is safe to assume that all images in self
exist.Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<C> Bundle for Cwhere
C: Component,
impl<C> Bundle for Cwhere
C: Component,
fn component_ids( components: &mut ComponentsRegistrator<'_>, ids: &mut impl FnMut(ComponentId), )
Source§fn get_component_ids(
components: &Components,
ids: &mut impl FnMut(Option<ComponentId>),
)
fn get_component_ids( components: &Components, ids: &mut impl FnMut(Option<ComponentId>), )
Source§impl<C> BundleFromComponents for Cwhere
C: Component,
impl<C> BundleFromComponents for Cwhere
C: Component,
Source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
Source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait>
(where Trait: Downcast
) to Box<dyn Any>
, which can then be
downcast
into Box<dyn ConcreteType>
where ConcreteType
implements Trait
.Source§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait>
(where Trait: Downcast
) to Rc<Any>
, which can then be further
downcast
into Rc<ConcreteType>
where ConcreteType
implements Trait
.Source§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait
(where Trait: Downcast
) to &Any
. This is needed since Rust cannot
generate &Any
’s vtable from &Trait
’s.Source§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait
(where Trait: Downcast
) to &Any
. This is needed since Rust cannot
generate &mut Any
’s vtable from &mut Trait
’s.Source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
Source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait>
(where Trait: Downcast
) to Box<dyn Any>
. Box<dyn Any>
can
then be further downcast
into Box<ConcreteType>
where ConcreteType
implements Trait
.Source§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait>
(where Trait: Downcast
) to Rc<Any>
. Rc<Any>
can then be
further downcast
into Rc<ConcreteType>
where ConcreteType
implements Trait
.Source§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait
(where Trait: Downcast
) to &Any
. This is needed since Rust cannot
generate &Any
’s vtable from &Trait
’s.Source§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait
(where Trait: Downcast
) to &Any
. This is needed since Rust cannot
generate &mut Any
’s vtable from &mut Trait
’s.Source§impl<T> DowncastSend for T
impl<T> DowncastSend for T
Source§impl<T> DowncastSync for T
impl<T> DowncastSync for T
Source§impl<C> DynamicBundle for Cwhere
C: Component,
impl<C> DynamicBundle for Cwhere
C: Component,
Source§unsafe fn get_components(
ptr: MovingPtr<'_, C>,
func: &mut impl FnMut(StorageType, OwningPtr<'_>),
) -> <C as DynamicBundle>::Effect
unsafe fn get_components( ptr: MovingPtr<'_, C>, func: &mut impl FnMut(StorageType, OwningPtr<'_>), ) -> <C as DynamicBundle>::Effect
Source§unsafe fn apply_effect(
_ptr: MovingPtr<'_, MaybeUninit<C>>,
_entity: &mut EntityWorldMut<'_>,
)
unsafe fn apply_effect( _ptr: MovingPtr<'_, MaybeUninit<C>>, _entity: &mut EntityWorldMut<'_>, )
Source§impl<T, W> HasTypeWitness<W> for Twhere
W: MakeTypeWitness<Arg = T>,
T: ?Sized,
impl<T, W> HasTypeWitness<W> for Twhere
W: MakeTypeWitness<Arg = T>,
T: ?Sized,
Source§impl<T> Identity for Twhere
T: ?Sized,
impl<T> Identity for Twhere
T: ?Sized,
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self
into a Left
variant of Either<Self, Self>
if into_left
is true
.
Converts self
into a Right
variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self
into a Left
variant of Either<Self, Self>
if into_left(&self)
returns true
.
Converts self
into a Right
variant of Either<Self, Self>
otherwise. Read more