Rename App/World::observe to add_observer, EntityWorldMut::observe_entity to observe. (#15754)

# Objective

- Closes #15752

Calling the functions `App::observe` and `World::observe` doesn't make
sense because you're not "observing" the `App` or `World`, you're adding
an observer that listens for an event that occurs *within* the `World`.
We should rename them to better fit this.

## Solution

Renames:
- `App::observe` -> `App::add_observer`
- `World::observe` -> `World::add_observer`
- `Commands::observe` -> `Commands::add_observer`
- `EntityWorldMut::observe_entity` -> `EntityWorldMut::observe`

(Note this isn't a breaking change as the original rename was introduced
earlier this cycle.)

## Testing

Reusing current tests.
This commit is contained in:
Christian Hughes 2024-10-09 08:39:29 -07:00 committed by GitHub
parent a2b53d46e7
commit 219b5930f1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
20 changed files with 168 additions and 106 deletions

View file

@ -106,15 +106,15 @@ fn add_listeners_to_hierarchy<const DENSITY: usize, const N: usize>(
world: &mut World,
) {
for e in roots.iter() {
world.entity_mut(*e).observe_entity(empty_listener::<N>);
world.entity_mut(*e).observe(empty_listener::<N>);
}
for e in leaves.iter() {
world.entity_mut(*e).observe_entity(empty_listener::<N>);
world.entity_mut(*e).observe(empty_listener::<N>);
}
let mut rng = deterministic_rand();
for e in nodes.iter() {
if rng.gen_bool(DENSITY as f64 / 100.0) {
world.entity_mut(*e).observe_entity(empty_listener::<N>);
world.entity_mut(*e).observe(empty_listener::<N>);
}
}
}

View file

@ -17,7 +17,7 @@ pub fn observe_simple(criterion: &mut Criterion) {
group.bench_function("trigger_simple", |bencher| {
let mut world = World::new();
world.observe(empty_listener_base);
world.add_observer(empty_listener_base);
bencher.iter(|| {
for _ in 0..10000 {
world.trigger(EventBase)
@ -29,7 +29,7 @@ pub fn observe_simple(criterion: &mut Criterion) {
let mut world = World::new();
let mut entities = vec![];
for _ in 0..10000 {
entities.push(world.spawn_empty().observe_entity(empty_listener_base).id());
entities.push(world.spawn_empty().observe(empty_listener_base).id());
}
entities.shuffle(&mut deterministic_rand());
bencher.iter(|| {

View file

@ -1267,7 +1267,7 @@ impl App {
/// # struct Friend;
/// #
/// // An observer system can be any system where the first parameter is a trigger
/// app.observe(|trigger: Trigger<Party>, friends: Query<Entity, With<Friend>>, mut commands: Commands| {
/// app.add_observer(|trigger: Trigger<Party>, friends: Query<Entity, With<Friend>>, mut commands: Commands| {
/// if trigger.event().friends_allowed {
/// for friend in friends.iter() {
/// commands.trigger_targets(Invite, friend);
@ -1275,11 +1275,11 @@ impl App {
/// }
/// });
/// ```
pub fn observe<E: Event, B: Bundle, M>(
pub fn add_observer<E: Event, B: Bundle, M>(
&mut self,
observer: impl IntoObserverSystem<E, B, M>,
) -> &mut Self {
self.world_mut().observe(observer);
self.world_mut().add_observer(observer);
self
}
}

View file

@ -25,7 +25,7 @@ pub(crate) fn send_events(world: &mut World, mut current_frame: Local<u32>) {
let path = format!("./screenshot-{}.png", *current_frame);
world
.spawn(Screenshot::primary_window())
.observe_entity(save_to_disk(path));
.observe(save_to_disk(path));
info!("Took a screenshot at frame {}.", *current_frame);
}
// Custom events are forwarded to the world.

View file

@ -315,7 +315,7 @@ struct MyEvent {
let mut world = World::new();
world.observe(|trigger: Trigger<MyEvent>| {
world.add_observer(|trigger: Trigger<MyEvent>| {
println!("{}", trigger.event().message);
});
@ -339,7 +339,7 @@ struct Explode;
let mut world = World::new();
let entity = world.spawn_empty().id();
world.observe(|trigger: Trigger<Explode>, mut commands: Commands| {
world.add_observer(|trigger: Trigger<Explode>, mut commands: Commands| {
println!("Entity {:?} goes BOOM!", trigger.entity());
commands.entity(trigger.entity()).despawn();
});

View file

@ -364,8 +364,29 @@ impl Observers {
}
impl World {
/// Spawns a "global" [`Observer`] and returns its [`Entity`].
pub fn observe<E: Event, B: Bundle, M>(
/// Spawns a "global" [`Observer`] which will watch for the given event.
/// Returns its [`Entity`] as a [`EntityWorldMut`].
///
/// **Calling [`observe`](EntityWorldMut::observe) on the returned
/// [`EntityWorldMut`] will observe the observer itself, which you very
/// likely do not want.**
///
/// # Example
///
/// ```
/// # use bevy_ecs::prelude::*;
/// #[derive(Component)]
/// struct A;
///
/// # let mut world = World::new();
/// world.add_observer(|_: Trigger<OnAdd, A>| {
/// // ...
/// });
/// world.add_observer(|_: Trigger<OnRemove, A>| {
/// // ...
/// });
/// ```
pub fn add_observer<E: Event, B: Bundle, M>(
&mut self,
system: impl IntoObserverSystem<E, B, M>,
) -> EntityWorldMut {
@ -593,10 +614,14 @@ mod tests {
let mut world = World::new();
world.init_resource::<Order>();
world.observe(|_: Trigger<OnAdd, A>, mut res: ResMut<Order>| res.observed("add"));
world.observe(|_: Trigger<OnInsert, A>, mut res: ResMut<Order>| res.observed("insert"));
world.observe(|_: Trigger<OnReplace, A>, mut res: ResMut<Order>| res.observed("replace"));
world.observe(|_: Trigger<OnRemove, A>, mut res: ResMut<Order>| res.observed("remove"));
world.add_observer(|_: Trigger<OnAdd, A>, mut res: ResMut<Order>| res.observed("add"));
world
.add_observer(|_: Trigger<OnInsert, A>, mut res: ResMut<Order>| res.observed("insert"));
world.add_observer(|_: Trigger<OnReplace, A>, mut res: ResMut<Order>| {
res.observed("replace");
});
world
.add_observer(|_: Trigger<OnRemove, A>, mut res: ResMut<Order>| res.observed("remove"));
let entity = world.spawn(A).id();
world.despawn(entity);
@ -611,10 +636,14 @@ mod tests {
let mut world = World::new();
world.init_resource::<Order>();
world.observe(|_: Trigger<OnAdd, A>, mut res: ResMut<Order>| res.observed("add"));
world.observe(|_: Trigger<OnInsert, A>, mut res: ResMut<Order>| res.observed("insert"));
world.observe(|_: Trigger<OnReplace, A>, mut res: ResMut<Order>| res.observed("replace"));
world.observe(|_: Trigger<OnRemove, A>, mut res: ResMut<Order>| res.observed("remove"));
world.add_observer(|_: Trigger<OnAdd, A>, mut res: ResMut<Order>| res.observed("add"));
world
.add_observer(|_: Trigger<OnInsert, A>, mut res: ResMut<Order>| res.observed("insert"));
world.add_observer(|_: Trigger<OnReplace, A>, mut res: ResMut<Order>| {
res.observed("replace");
});
world
.add_observer(|_: Trigger<OnRemove, A>, mut res: ResMut<Order>| res.observed("remove"));
let mut entity = world.spawn_empty();
entity.insert(A);
@ -631,10 +660,14 @@ mod tests {
let mut world = World::new();
world.init_resource::<Order>();
world.observe(|_: Trigger<OnAdd, S>, mut res: ResMut<Order>| res.observed("add"));
world.observe(|_: Trigger<OnInsert, S>, mut res: ResMut<Order>| res.observed("insert"));
world.observe(|_: Trigger<OnReplace, S>, mut res: ResMut<Order>| res.observed("replace"));
world.observe(|_: Trigger<OnRemove, S>, mut res: ResMut<Order>| res.observed("remove"));
world.add_observer(|_: Trigger<OnAdd, S>, mut res: ResMut<Order>| res.observed("add"));
world
.add_observer(|_: Trigger<OnInsert, S>, mut res: ResMut<Order>| res.observed("insert"));
world.add_observer(|_: Trigger<OnReplace, S>, mut res: ResMut<Order>| {
res.observed("replace");
});
world
.add_observer(|_: Trigger<OnRemove, S>, mut res: ResMut<Order>| res.observed("remove"));
let mut entity = world.spawn_empty();
entity.insert(S);
@ -653,10 +686,14 @@ mod tests {
let entity = world.spawn(A).id();
world.observe(|_: Trigger<OnAdd, A>, mut res: ResMut<Order>| res.observed("add"));
world.observe(|_: Trigger<OnInsert, A>, mut res: ResMut<Order>| res.observed("insert"));
world.observe(|_: Trigger<OnReplace, A>, mut res: ResMut<Order>| res.observed("replace"));
world.observe(|_: Trigger<OnRemove, A>, mut res: ResMut<Order>| res.observed("remove"));
world.add_observer(|_: Trigger<OnAdd, A>, mut res: ResMut<Order>| res.observed("add"));
world
.add_observer(|_: Trigger<OnInsert, A>, mut res: ResMut<Order>| res.observed("insert"));
world.add_observer(|_: Trigger<OnReplace, A>, mut res: ResMut<Order>| {
res.observed("replace");
});
world
.add_observer(|_: Trigger<OnRemove, A>, mut res: ResMut<Order>| res.observed("remove"));
// TODO: ideally this flush is not necessary, but right now observe() returns WorldEntityMut
// and therefore does not automatically flush.
@ -672,26 +709,26 @@ mod tests {
fn observer_order_recursive() {
let mut world = World::new();
world.init_resource::<Order>();
world.observe(
world.add_observer(
|obs: Trigger<OnAdd, A>, mut res: ResMut<Order>, mut commands: Commands| {
res.observed("add_a");
commands.entity(obs.entity()).insert(B);
},
);
world.observe(
world.add_observer(
|obs: Trigger<OnRemove, A>, mut res: ResMut<Order>, mut commands: Commands| {
res.observed("remove_a");
commands.entity(obs.entity()).remove::<B>();
},
);
world.observe(
world.add_observer(
|obs: Trigger<OnAdd, B>, mut res: ResMut<Order>, mut commands: Commands| {
res.observed("add_b");
commands.entity(obs.entity()).remove::<A>();
},
);
world.observe(|_: Trigger<OnRemove, B>, mut res: ResMut<Order>| {
world.add_observer(|_: Trigger<OnRemove, B>, mut res: ResMut<Order>| {
res.observed("remove_b");
});
@ -709,11 +746,11 @@ mod tests {
fn observer_trigger_ref() {
let mut world = World::new();
world.observe(|mut trigger: Trigger<EventWithData>| trigger.event_mut().counter += 1);
world.observe(|mut trigger: Trigger<EventWithData>| trigger.event_mut().counter += 2);
world.observe(|mut trigger: Trigger<EventWithData>| trigger.event_mut().counter += 4);
world.add_observer(|mut trigger: Trigger<EventWithData>| trigger.event_mut().counter += 1);
world.add_observer(|mut trigger: Trigger<EventWithData>| trigger.event_mut().counter += 2);
world.add_observer(|mut trigger: Trigger<EventWithData>| trigger.event_mut().counter += 4);
// This flush is required for the last observer to be called when triggering the event,
// due to `World::observe` returning `WorldEntityMut`.
// due to `World::add_observer` returning `WorldEntityMut`.
world.flush();
let mut event = EventWithData { counter: 0 };
@ -725,11 +762,17 @@ mod tests {
fn observer_trigger_targets_ref() {
let mut world = World::new();
world.observe(|mut trigger: Trigger<EventWithData, A>| trigger.event_mut().counter += 1);
world.observe(|mut trigger: Trigger<EventWithData, B>| trigger.event_mut().counter += 2);
world.observe(|mut trigger: Trigger<EventWithData, A>| trigger.event_mut().counter += 4);
world.add_observer(|mut trigger: Trigger<EventWithData, A>| {
trigger.event_mut().counter += 1;
});
world.add_observer(|mut trigger: Trigger<EventWithData, B>| {
trigger.event_mut().counter += 2;
});
world.add_observer(|mut trigger: Trigger<EventWithData, A>| {
trigger.event_mut().counter += 4;
});
// This flush is required for the last observer to be called when triggering the event,
// due to `World::observe` returning `WorldEntityMut`.
// due to `World::add_observer` returning `WorldEntityMut`.
world.flush();
let mut event = EventWithData { counter: 0 };
@ -743,8 +786,8 @@ mod tests {
let mut world = World::new();
world.init_resource::<Order>();
world.observe(|_: Trigger<OnAdd, A>, mut res: ResMut<Order>| res.observed("add_1"));
world.observe(|_: Trigger<OnAdd, A>, mut res: ResMut<Order>| res.observed("add_2"));
world.add_observer(|_: Trigger<OnAdd, A>, mut res: ResMut<Order>| res.observed("add_1"));
world.add_observer(|_: Trigger<OnAdd, A>, mut res: ResMut<Order>| res.observed("add_2"));
world.spawn(A).flush();
assert_eq!(vec!["add_1", "add_2"], world.resource::<Order>().0);
@ -782,7 +825,9 @@ mod tests {
world.register_component::<A>();
world.register_component::<B>();
world.observe(|_: Trigger<OnAdd, (A, B)>, mut res: ResMut<Order>| res.observed("add_ab"));
world.add_observer(|_: Trigger<OnAdd, (A, B)>, mut res: ResMut<Order>| {
res.observed("add_ab");
});
let entity = world.spawn(A).id();
world.entity_mut(entity).insert(B);
@ -795,7 +840,9 @@ mod tests {
let mut world = World::new();
let observer = world
.observe(|_: Trigger<OnAdd, A>| panic!("Observer triggered after being despawned."))
.add_observer(|_: Trigger<OnAdd, A>| {
panic!("Observer triggered after being despawned.")
})
.id();
world.despawn(observer);
world.spawn(A).flush();
@ -809,10 +856,14 @@ mod tests {
let entity = world.spawn((A, B)).flush();
world.observe(|_: Trigger<OnRemove, A>, mut res: ResMut<Order>| res.observed("remove_a"));
world.add_observer(|_: Trigger<OnRemove, A>, mut res: ResMut<Order>| {
res.observed("remove_a");
});
let observer = world
.observe(|_: Trigger<OnRemove, B>| panic!("Observer triggered after being despawned."))
.add_observer(|_: Trigger<OnRemove, B>| {
panic!("Observer triggered after being despawned.")
})
.flush();
world.despawn(observer);
@ -826,7 +877,9 @@ mod tests {
let mut world = World::new();
world.init_resource::<Order>();
world.observe(|_: Trigger<OnAdd, (A, B)>, mut res: ResMut<Order>| res.observed("add_ab"));
world.add_observer(|_: Trigger<OnAdd, (A, B)>, mut res: ResMut<Order>| {
res.observed("add_ab");
});
world.spawn((A, B)).flush();
assert_eq!(vec!["add_ab"], world.resource::<Order>().0);
@ -839,8 +892,8 @@ mod tests {
world
.spawn_empty()
.observe_entity(|_: Trigger<EventA>| panic!("Trigger routed to non-targeted entity."));
world.observe(move |obs: Trigger<EventA>, mut res: ResMut<Order>| {
.observe(|_: Trigger<EventA>| panic!("Trigger routed to non-targeted entity."));
world.add_observer(move |obs: Trigger<EventA>, mut res: ResMut<Order>| {
assert_eq!(obs.entity(), Entity::PLACEHOLDER);
res.observed("event_a");
});
@ -860,12 +913,12 @@ mod tests {
world
.spawn_empty()
.observe_entity(|_: Trigger<EventA>| panic!("Trigger routed to non-targeted entity."));
.observe(|_: Trigger<EventA>| panic!("Trigger routed to non-targeted entity."));
let entity = world
.spawn_empty()
.observe_entity(|_: Trigger<EventA>, mut res: ResMut<Order>| res.observed("a_1"))
.observe(|_: Trigger<EventA>, mut res: ResMut<Order>| res.observed("a_1"))
.id();
world.observe(move |obs: Trigger<EventA>, mut res: ResMut<Order>| {
world.add_observer(move |obs: Trigger<EventA>, mut res: ResMut<Order>| {
assert_eq!(obs.entity(), entity);
res.observed("a_2");
});
@ -931,14 +984,14 @@ mod tests {
let parent = world
.spawn_empty()
.observe_entity(|_: Trigger<EventPropagating>, mut res: ResMut<Order>| {
.observe(|_: Trigger<EventPropagating>, mut res: ResMut<Order>| {
res.observed("parent");
})
.id();
let child = world
.spawn(Parent(parent))
.observe_entity(|_: Trigger<EventPropagating>, mut res: ResMut<Order>| {
.observe(|_: Trigger<EventPropagating>, mut res: ResMut<Order>| {
res.observed("child");
})
.id();
@ -958,14 +1011,14 @@ mod tests {
let parent = world
.spawn_empty()
.observe_entity(|_: Trigger<EventPropagating>, mut res: ResMut<Order>| {
.observe(|_: Trigger<EventPropagating>, mut res: ResMut<Order>| {
res.observed("parent");
})
.id();
let child = world
.spawn(Parent(parent))
.observe_entity(|_: Trigger<EventPropagating>, mut res: ResMut<Order>| {
.observe(|_: Trigger<EventPropagating>, mut res: ResMut<Order>| {
res.observed("child");
})
.id();
@ -988,14 +1041,14 @@ mod tests {
let parent = world
.spawn_empty()
.observe_entity(|_: Trigger<EventPropagating>, mut res: ResMut<Order>| {
.observe(|_: Trigger<EventPropagating>, mut res: ResMut<Order>| {
res.observed("parent");
})
.id();
let child = world
.spawn(Parent(parent))
.observe_entity(|_: Trigger<EventPropagating>, mut res: ResMut<Order>| {
.observe(|_: Trigger<EventPropagating>, mut res: ResMut<Order>| {
res.observed("child");
})
.id();
@ -1018,14 +1071,14 @@ mod tests {
let parent = world
.spawn_empty()
.observe_entity(|_: Trigger<EventPropagating>, mut res: ResMut<Order>| {
.observe(|_: Trigger<EventPropagating>, mut res: ResMut<Order>| {
res.observed("parent");
})
.id();
let child = world
.spawn(Parent(parent))
.observe_entity(
.observe(
|mut trigger: Trigger<EventPropagating>, mut res: ResMut<Order>| {
res.observed("child");
trigger.propagate(false);
@ -1048,21 +1101,21 @@ mod tests {
let parent = world
.spawn_empty()
.observe_entity(|_: Trigger<EventPropagating>, mut res: ResMut<Order>| {
.observe(|_: Trigger<EventPropagating>, mut res: ResMut<Order>| {
res.observed("parent");
})
.id();
let child_a = world
.spawn(Parent(parent))
.observe_entity(|_: Trigger<EventPropagating>, mut res: ResMut<Order>| {
.observe(|_: Trigger<EventPropagating>, mut res: ResMut<Order>| {
res.observed("child_a");
})
.id();
let child_b = world
.spawn(Parent(parent))
.observe_entity(|_: Trigger<EventPropagating>, mut res: ResMut<Order>| {
.observe(|_: Trigger<EventPropagating>, mut res: ResMut<Order>| {
res.observed("child_b");
})
.id();
@ -1085,7 +1138,7 @@ mod tests {
let entity = world
.spawn_empty()
.observe_entity(|_: Trigger<EventPropagating>, mut res: ResMut<Order>| {
.observe(|_: Trigger<EventPropagating>, mut res: ResMut<Order>| {
res.observed("event");
})
.id();
@ -1105,14 +1158,14 @@ mod tests {
let parent_a = world
.spawn_empty()
.observe_entity(|_: Trigger<EventPropagating>, mut res: ResMut<Order>| {
.observe(|_: Trigger<EventPropagating>, mut res: ResMut<Order>| {
res.observed("parent_a");
})
.id();
let child_a = world
.spawn(Parent(parent_a))
.observe_entity(
.observe(
|mut trigger: Trigger<EventPropagating>, mut res: ResMut<Order>| {
res.observed("child_a");
trigger.propagate(false);
@ -1122,14 +1175,14 @@ mod tests {
let parent_b = world
.spawn_empty()
.observe_entity(|_: Trigger<EventPropagating>, mut res: ResMut<Order>| {
.observe(|_: Trigger<EventPropagating>, mut res: ResMut<Order>| {
res.observed("parent_b");
})
.id();
let child_b = world
.spawn(Parent(parent_b))
.observe_entity(|_: Trigger<EventPropagating>, mut res: ResMut<Order>| {
.observe(|_: Trigger<EventPropagating>, mut res: ResMut<Order>| {
res.observed("child_b");
})
.id();
@ -1150,7 +1203,9 @@ mod tests {
let mut world = World::new();
world.init_resource::<Order>();
world.observe(|_: Trigger<EventPropagating>, mut res: ResMut<Order>| res.observed("event"));
world.add_observer(|_: Trigger<EventPropagating>, mut res: ResMut<Order>| {
res.observed("event");
});
let grandparent = world.spawn_empty().id();
let parent = world.spawn(Parent(grandparent)).id();
@ -1169,7 +1224,7 @@ mod tests {
let mut world = World::new();
world.init_resource::<Order>();
world.observe(
world.add_observer(
|trigger: Trigger<EventPropagating>, query: Query<&A>, mut res: ResMut<Order>| {
if query.get(trigger.entity()).is_ok() {
res.observed("event");
@ -1196,7 +1251,7 @@ mod tests {
let mut world = World::new();
// Observe the removal of A - this will run during despawn
world.observe(|_: Trigger<OnRemove, A>, mut cmd: Commands| {
world.add_observer(|_: Trigger<OnRemove, A>, mut cmd: Commands| {
// Spawn a new entity - this reserves a new ID and requires a flush
// afterward before Entities::free can be called.
cmd.spawn_empty();
@ -1224,7 +1279,7 @@ mod tests {
let mut world = World::new();
// This fails because `ResA` is not present in the world
world.observe(|_: Trigger<EventA>, _: Res<ResA>, mut commands: Commands| {
world.add_observer(|_: Trigger<EventA>, _: Res<ResA>, mut commands: Commands| {
commands.insert_resource(ResB);
});
world.trigger(EventA);
@ -1241,7 +1296,7 @@ mod tests {
struct ResA;
let mut world = World::new();
world.observe(
world.add_observer(
|_: Trigger<EventA>, mut params: ParamSet<(Query<Entity>, Commands)>| {
params.p1().insert_resource(ResA);
},

View file

@ -111,7 +111,7 @@ pub type ObserverRunner = fn(DeferredWorld, ObserverTrigger, PtrMut, propagate:
/// message: String,
/// }
///
/// world.observe(|trigger: Trigger<Speak>| {
/// world.add_observer(|trigger: Trigger<Speak>| {
/// println!("{}", trigger.event().message);
/// });
///
@ -124,7 +124,7 @@ pub type ObserverRunner = fn(DeferredWorld, ObserverTrigger, PtrMut, propagate:
/// });
/// ```
///
/// Notice that we used [`World::observe`]. This is just a shorthand for spawning an [`Observer`] manually:
/// Notice that we used [`World::add_observer`]. This is just a shorthand for spawning an [`Observer`] manually:
///
/// ```
/// # use bevy_ecs::prelude::*;
@ -132,7 +132,7 @@ pub type ObserverRunner = fn(DeferredWorld, ObserverTrigger, PtrMut, propagate:
/// # #[derive(Event)]
/// # struct Speak;
/// // These are functionally the same:
/// world.observe(|trigger: Trigger<Speak>| {});
/// world.add_observer(|trigger: Trigger<Speak>| {});
/// world.spawn(Observer::new(|trigger: Trigger<Speak>| {}));
/// ```
///
@ -145,7 +145,7 @@ pub type ObserverRunner = fn(DeferredWorld, ObserverTrigger, PtrMut, propagate:
/// # struct PrintNames;
/// # #[derive(Component, Debug)]
/// # struct Name;
/// world.observe(|trigger: Trigger<PrintNames>, names: Query<&Name>| {
/// world.add_observer(|trigger: Trigger<PrintNames>, names: Query<&Name>| {
/// for name in &names {
/// println!("{name:?}");
/// }
@ -163,7 +163,7 @@ pub type ObserverRunner = fn(DeferredWorld, ObserverTrigger, PtrMut, propagate:
/// # struct SpawnThing;
/// # #[derive(Component, Debug)]
/// # struct Thing;
/// world.observe(|trigger: Trigger<SpawnThing>, mut commands: Commands| {
/// world.add_observer(|trigger: Trigger<SpawnThing>, mut commands: Commands| {
/// commands.spawn(Thing);
/// });
/// ```
@ -177,7 +177,7 @@ pub type ObserverRunner = fn(DeferredWorld, ObserverTrigger, PtrMut, propagate:
/// # struct A;
/// # #[derive(Event)]
/// # struct B;
/// world.observe(|trigger: Trigger<A>, mut commands: Commands| {
/// world.add_observer(|trigger: Trigger<A>, mut commands: Commands| {
/// commands.trigger(B);
/// });
/// ```
@ -195,7 +195,7 @@ pub type ObserverRunner = fn(DeferredWorld, ObserverTrigger, PtrMut, propagate:
/// #[derive(Event)]
/// struct Explode;
///
/// world.observe(|trigger: Trigger<Explode>, mut commands: Commands| {
/// world.add_observer(|trigger: Trigger<Explode>, mut commands: Commands| {
/// println!("Entity {:?} goes BOOM!", trigger.entity());
/// commands.entity(trigger.entity()).despawn();
/// });
@ -228,12 +228,12 @@ pub type ObserverRunner = fn(DeferredWorld, ObserverTrigger, PtrMut, propagate:
/// # let e2 = world.spawn_empty().id();
/// # #[derive(Event)]
/// # struct Explode;
/// world.entity_mut(e1).observe_entity(|trigger: Trigger<Explode>, mut commands: Commands| {
/// world.entity_mut(e1).observe(|trigger: Trigger<Explode>, mut commands: Commands| {
/// println!("Boom!");
/// commands.entity(trigger.entity()).despawn();
/// });
///
/// world.entity_mut(e2).observe_entity(|trigger: Trigger<Explode>, mut commands: Commands| {
/// world.entity_mut(e2).observe(|trigger: Trigger<Explode>, mut commands: Commands| {
/// println!("The explosion fizzles! This entity is immune!");
/// });
/// ```
@ -241,7 +241,7 @@ pub type ObserverRunner = fn(DeferredWorld, ObserverTrigger, PtrMut, propagate:
/// 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_entity`] to add entity-specific observer logic are (once again)
/// The examples above calling [`EntityWorldMut::observe`] to add entity-specific observer logic are (once again)
/// just shorthand for spawning an [`Observer`] directly:
///
/// ```

View file

@ -832,8 +832,13 @@ impl<'w, 's> Commands<'w, 's> {
self.queue(TriggerEvent { event, targets });
}
/// Spawns an [`Observer`] and returns the [`EntityCommands`] associated with the entity that stores the observer.
pub fn observe<E: Event, B: Bundle, M>(
/// Spawns an [`Observer`] and returns the [`EntityCommands`] associated
/// with the entity that stores the observer.
///
/// **Calling [`observe`](EntityCommands::observe) on the returned
/// [`EntityCommands`] will observe the observer itself, which you very
/// likely do not want.**
pub fn add_observer<E: Event, B: Bundle, M>(
&mut self,
observer: impl IntoObserverSystem<E, B, M>,
) -> EntityCommands {
@ -1923,7 +1928,7 @@ fn observe<E: Event, B: Bundle, M>(
) -> impl EntityCommand {
move |entity: Entity, world: &mut World| {
if let Ok(mut entity) = world.get_entity_mut(entity) {
entity.observe_entity(observer);
entity.observe(observer);
}
}
}

View file

@ -70,7 +70,7 @@ mod tests {
fn b() {}
let mut world = World::new();
world.observe(a.pipe(b));
world.add_observer(a.pipe(b));
}
#[test]
@ -81,6 +81,6 @@ mod tests {
fn b(_: In<u32>) {}
let mut world = World::new();
world.observe(a.pipe(b));
world.add_observer(a.pipe(b));
}
}

View file

@ -1854,7 +1854,7 @@ impl<'w> EntityWorldMut<'w> {
/// Creates an [`Observer`] listening for events of type `E` targeting this entity.
/// In order to trigger the callback the entity must also match the query when the event is fired.
pub fn observe_entity<E: Event, B: Bundle, M>(
pub fn observe<E: Event, B: Bundle, M>(
&mut self,
observer: impl IntoObserverSystem<E, B, M>,
) -> &mut Self {

View file

@ -458,8 +458,10 @@ impl Plugin for PbrPlugin {
)
.init_resource::<LightMeta>();
render_app.world_mut().observe(add_light_view_entities);
render_app.world_mut().observe(remove_light_view_entities);
render_app.world_mut().add_observer(add_light_view_entities);
render_app
.world_mut()
.add_observer(remove_light_view_entities);
let shadow_pass_node = ShadowPassNode::new(render_app.world_mut());
let mut graph = render_app.world_mut().resource_mut::<RenderGraph>();

View file

@ -11,7 +11,7 @@
//! # use bevy_picking::prelude::*;
//! # let mut world = World::default();
//! world.spawn_empty()
//! .observe_entity(|trigger: Trigger<Pointer<Over>>| {
//! .observe(|trigger: Trigger<Pointer<Over>>| {
//! println!("I am being hovered over");
//! });
//! ```

View file

@ -15,7 +15,7 @@
//! # struct MyComponent;
//! # let mut world = World::new();
//! world.spawn(MyComponent)
//! .observe_entity(|mut trigger: Trigger<Pointer<Click>>| {
//! .observe(|mut trigger: Trigger<Pointer<Click>>| {
//! // Get the underlying event type
//! let click_event: &Pointer<Click> = trigger.event();
//! // Stop the event from bubbling up the entity hierarchjy

View file

@ -85,12 +85,12 @@ pub struct SyncWorldPlugin;
impl Plugin for SyncWorldPlugin {
fn build(&self, app: &mut bevy_app::App) {
app.init_resource::<PendingSyncEntity>();
app.observe(
app.add_observer(
|trigger: Trigger<OnAdd, SyncToRenderWorld>, mut pending: ResMut<PendingSyncEntity>| {
pending.push(EntityRecord::Added(trigger.entity()));
},
);
app.observe(
app.add_observer(
|trigger: Trigger<OnRemove, SyncToRenderWorld>,
mut pending: ResMut<PendingSyncEntity>,
query: Query<&RenderEntity>| {
@ -248,12 +248,12 @@ mod tests {
let mut render_world = World::new();
main_world.init_resource::<PendingSyncEntity>();
main_world.observe(
main_world.add_observer(
|trigger: Trigger<OnAdd, SyncToRenderWorld>, mut pending: ResMut<PendingSyncEntity>| {
pending.push(EntityRecord::Added(trigger.entity()));
},
);
main_world.observe(
main_world.add_observer(
|trigger: Trigger<OnRemove, SyncToRenderWorld>,
mut pending: ResMut<PendingSyncEntity>,
query: Query<&RenderEntity>| {

View file

@ -581,7 +581,7 @@ mod tests {
fn observe_trigger(app: &mut App, scene_id: InstanceId, scene_entity: Entity) {
// Add observer
app.world_mut().observe(
app.world_mut().add_observer(
move |trigger: Trigger<SceneInstanceReady>,
scene_spawner: Res<SceneSpawner>,
mut trigger_count: ResMut<TriggerCount>| {

View file

@ -31,7 +31,7 @@ impl Plugin for CursorPlugin {
.init_resource::<CustomCursorCache>()
.add_systems(Last, update_cursors);
app.observe(on_remove_cursor_icon);
app.add_observer(on_remove_cursor_icon);
}
}

View file

@ -24,7 +24,7 @@ fn main() {
.add_systems(Startup, setup)
.add_systems(Update, setup_scene_once_loaded.before(animate_targets))
.add_systems(Update, (keyboard_animation_control, simulate_particles))
.observe(observe_on_step)
.add_observer(observe_on_step)
.run();
}

View file

@ -14,7 +14,7 @@ fn main() {
attack_armor.run_if(on_timer(Duration::from_millis(200))),
)
// Add a global observer that will emit a line whenever an attack hits an entity.
.observe(attack_hits)
.add_observer(attack_hits)
.run();
}

View file

@ -15,7 +15,7 @@ fn main() {
.add_systems(Update, (draw_shapes, handle_click))
// Observers are systems that run when an event is "triggered". This observer runs whenever
// `ExplodeMines` is triggered.
.observe(
.add_observer(
|trigger: Trigger<ExplodeMines>,
mines: Query<&Mine>,
index: Res<SpatialIndex>,
@ -35,10 +35,10 @@ fn main() {
},
)
// This observer runs whenever the `Mine` component is added to an entity, and places it in a simple spatial index.
.observe(on_add_mine)
.add_observer(on_add_mine)
// This observer runs whenever the `Mine` component is removed from an entity (including despawning it)
// and removes it from the spatial index.
.observe(on_remove_mine)
.add_observer(on_remove_mine)
.run();
}

View file

@ -17,7 +17,7 @@ fn main() {
// This system will remove a component after two seconds.
.add_systems(Update, remove_component)
// This observer will react to the removal of the component.
.observe(react_on_removal)
.add_observer(react_on_removal)
.run();
}