pub struct Observer<T, B>where
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 SystemParams:
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, B> Observer<E, B>
impl<E, B> Observer<E, B>
sourcepub fn new<M>(system: impl IntoObserverSystem<E, B, M>) -> Observer<E, B>
pub fn new<M>(system: impl IntoObserverSystem<E, B, M>) -> Observer<E, B>
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).
Examples found in repository?
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117
fn setup(mut commands: Commands) {
commands.spawn(Camera2dBundle::default());
commands.spawn(
TextBundle::from_section(
"Click on a \"Mine\" to trigger it.\n\
When it explodes it will trigger all overlapping mines.",
TextStyle {
color: Color::WHITE,
..default()
},
)
.with_style(Style {
position_type: PositionType::Absolute,
top: Val::Px(12.),
left: Val::Px(12.),
..default()
}),
);
let mut rng = ChaCha8Rng::seed_from_u64(19878367467713);
commands
.spawn(Mine::random(&mut rng))
// Observers can watch for events targeting a specific entity.
// This will create a new observer that runs whenever the Explode event
// is triggered for this spawned entity.
.observe(explode_mine);
// We want to spawn a bunch of mines. We could just call the code above for each of them.
// That would create a new observer instance for every Mine entity. Having duplicate observers
// generally isn't worth worrying about as the overhead is low. But if you want to be maximally efficient,
// you can reuse observers across entities.
//
// First, observers are actually just entities with the Observer component! The `observe()` functions
// you've seen so far in this example are just shorthand for manually spawning an observer.
let mut observer = Observer::new(explode_mine);
// As we spawn entities, we can make this observer watch each of them:
for _ in 0..1000 {
let entity = commands.spawn(Mine::random(&mut rng)).id();
observer.watch_entity(entity);
}
// By spawning the Observer component, it becomes active!
commands.spawn(observer);
}sourcepub fn with_entity(self, entity: Entity) -> Observer<E, B>
pub fn with_entity(self, entity: Entity) -> Observer<E, B>
sourcepub fn watch_entity(&mut self, entity: Entity)
pub fn watch_entity(&mut self, entity: Entity)
Observe the given entity. This will cause the Observer to run whenever the Event is triggered
for the entity.
Note that if this is called after an Observer is spawned, it will produce no effects.
Examples found in repository?
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117
fn setup(mut commands: Commands) {
commands.spawn(Camera2dBundle::default());
commands.spawn(
TextBundle::from_section(
"Click on a \"Mine\" to trigger it.\n\
When it explodes it will trigger all overlapping mines.",
TextStyle {
color: Color::WHITE,
..default()
},
)
.with_style(Style {
position_type: PositionType::Absolute,
top: Val::Px(12.),
left: Val::Px(12.),
..default()
}),
);
let mut rng = ChaCha8Rng::seed_from_u64(19878367467713);
commands
.spawn(Mine::random(&mut rng))
// Observers can watch for events targeting a specific entity.
// This will create a new observer that runs whenever the Explode event
// is triggered for this spawned entity.
.observe(explode_mine);
// We want to spawn a bunch of mines. We could just call the code above for each of them.
// That would create a new observer instance for every Mine entity. Having duplicate observers
// generally isn't worth worrying about as the overhead is low. But if you want to be maximally efficient,
// you can reuse observers across entities.
//
// First, observers are actually just entities with the Observer component! The `observe()` functions
// you've seen so far in this example are just shorthand for manually spawning an observer.
let mut observer = Observer::new(explode_mine);
// As we spawn entities, we can make this observer watch each of them:
for _ in 0..1000 {
let entity = commands.spawn(Mine::random(&mut rng)).id();
observer.watch_entity(entity);
}
// By spawning the Observer component, it becomes active!
commands.spawn(observer);
}sourcepub fn with_component(self, component: ComponentId) -> Observer<E, B>
pub fn with_component(self, component: ComponentId) -> Observer<E, B>
sourcepub unsafe fn with_event(self, event: ComponentId) -> Observer<E, B>
pub unsafe fn with_event(self, event: ComponentId) -> Observer<E, B>
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, B> Component for Observer<E, B>
impl<E, B> 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, 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 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.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,
fn get_components(self, func: &mut impl FnMut(StorageType, OwningPtr<'_>))
source§impl<S> FromSample<S> for S
impl<S> FromSample<S> for S
fn from_sample_(s: S) -> S
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