pub struct Observer<T: 'static, B: Bundle> { /* private fields */ }
Expand description
An Observer
system. Add this Component
to an Entity
to turn it into an “observer”.
Observers listen for a “trigger” of a specific Event
. Events are triggered by calling World::trigger
or World::trigger_targets
.
Note that “buffered” events sent using EventReader
and EventWriter
are not automatically triggered. They must be triggered at a specific
point in the schedule.
§Usage
The simplest usage of the observer pattern looks like this:
#[derive(Event)]
struct Speak {
message: String,
}
world.observe(|trigger: Trigger<Speak>| {
println!("{}", trigger.event().message);
});
// Observers currently require a flush() to be registered. In the context of schedules,
// this will generally be done for you.
world.flush();
world.trigger(Speak {
message: "Hello!".into(),
});
Notice that we used World::observe
. This is just a shorthand for spawning an Observer
manually:
// These are functionally the same:
world.observe(|trigger: Trigger<Speak>| {});
world.spawn(Observer::new(|trigger: Trigger<Speak>| {}));
Observers are systems. They can access arbitrary World
data by adding SystemParam
s:
world.observe(|trigger: Trigger<PrintNames>, names: Query<&Name>| {
for name in &names {
println!("{name:?}");
}
});
Note that Trigger
must always be the first parameter.
You can also add Commands
, which means you can spawn new entities, insert new components, etc:
world.observe(|trigger: Trigger<SpawnThing>, mut commands: Commands| {
commands.spawn(Thing);
});
Observers can also trigger new events:
world.observe(|trigger: Trigger<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!
Events can be triggered for entities, which will be passed to the Observer
:
#[derive(Event)]
struct Explode;
world.observe(|trigger: Trigger<Explode>, mut commands: Commands| {
println!("Entity {:?} goes BOOM!", trigger.entity());
commands.entity(trigger.entity()).despawn();
});
world.flush();
world.trigger_targets(Explode, entity);
You can trigger multiple entities at once:
world.trigger_targets(Explode, [e1, e2]);
Observers can also watch specific entities, which enables you to assign entity-specific logic:
world.entity_mut(e1).observe(|trigger: Trigger<Explode>, mut commands: Commands| {
println!("Boom!");
commands.entity(trigger.entity()).despawn();
});
world.entity_mut(e2).observe(|trigger: Trigger<Explode>, mut commands: Commands| {
println!("The explosion fizzles! This entity is immune!");
});
If all entities watched by a given Observer
are despawned, the Observer
entity will also be despawned.
This protects against observer “garbage” building up over time.
The examples above calling EntityWorldMut::observe
to add entity-specific observer logic are (once again)
just shorthand for spawning an Observer
directly:
let mut observer = Observer::new(|trigger: Trigger<Explode>| {});
observer.watch_entity(entity);
world.spawn(observer);
Note that the Observer
component is not added to the entity it is observing. Observers should always be their own entities!
You can call Observer::watch_entity
more than once, which allows you to watch multiple entities with the same Observer
.
When first added, Observer
will also create an ObserverState
component, which registers the observer with the World
and
serves as the “source of truth” of the observer.
Implementations§
source§impl<E: Event, B: Bundle> Observer<E, B>
impl<E: Event, B: Bundle> Observer<E, B>
sourcepub fn new<M>(system: impl IntoObserverSystem<E, B, M>) -> Self
pub fn new<M>(system: impl IntoObserverSystem<E, B, M>) -> Self
Creates a new Observer
, which defaults to a “global” observer. This means it will run whenever the event E
is triggered
for any entity (or no entity).
sourcepub fn with_entity(self, entity: Entity) -> Self
pub fn with_entity(self, entity: Entity) -> Self
sourcepub fn watch_entity(&mut self, entity: Entity)
pub fn watch_entity(&mut self, entity: Entity)
sourcepub fn with_component(self, component: ComponentId) -> Self
pub fn with_component(self, component: ComponentId) -> Self
sourcepub unsafe fn with_event(self, event: ComponentId) -> Self
pub unsafe fn with_event(self, event: ComponentId) -> Self
Observe the given event
. This will cause the Observer
to run whenever an event with the given ComponentId
is triggered.
§Safety
The type of the event
ComponentId
must match the actual value
of the event passed into the observer system.
Trait Implementations§
source§impl<E: Event, B: Bundle> Component for Observer<E, B>
impl<E: Event, B: Bundle> Component for Observer<E, B>
source§const STORAGE_TYPE: StorageType = StorageType::SparseSet
const STORAGE_TYPE: StorageType = StorageType::SparseSet
source§fn register_component_hooks(hooks: &mut ComponentHooks)
fn register_component_hooks(hooks: &mut ComponentHooks)
ComponentHooks
.Auto Trait Implementations§
impl<T, B> Freeze for Observer<T, B>
impl<T, B> !RefUnwindSafe for Observer<T, B>
impl<T, B> Send for Observer<T, B>
impl<T, B> Sync for Observer<T, B>
impl<T, B> Unpin for Observer<T, B>
impl<T, B> !UnwindSafe for Observer<T, B>
Blanket Implementations§
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 Components, storages: &mut Storages, ids: &mut impl FnMut(ComponentId) )
unsafe fn from_components<T, F>(ctx: &mut T, func: &mut F) -> C
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<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.