Skip to content

Commit 1df54ed

Browse files
Add methods Observer::with_entities and Observer::watch_entities (#20274)
# Objective From time to time, I find myself observing multiple entities with the same `Observer`. Right now this can only be achieved by calling [`with_entity`](https://docs.rs/bevy/latest/bevy/ecs/observer/struct.Observer.html#method.with_entity) or [`watch_entity`](https://docs.rs/bevy/latest/bevy/ecs/observer/struct.Observer.html#method.watch_entity) for each entity to watch. This PR provides versions of these two methods to watch multiple entities with a single call. ## Testing Added a simple test. --------- Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
1 parent 6bb0473 commit 1df54ed

File tree

3 files changed

+49
-12
lines changed

3 files changed

+49
-12
lines changed

crates/bevy_ecs/src/observer/distributed_storage.rs

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -200,8 +200,7 @@ use crate::prelude::ReflectComponent;
200200
///
201201
/// Note that the [`Observer`] component is not added to the entity it is observing. Observers should always be their own entities!
202202
///
203-
/// You can call [`Observer::watch_entity`] more than once, which allows you to watch multiple entities with the same [`Observer`].
204-
/// serves as the "source of truth" of the observer.
203+
/// You can call [`Observer::watch_entity`] more than once or [`Observer::watch_entities`] to watch multiple entities with the same [`Observer`].
205204
///
206205
/// [`SystemParam`]: crate::system::SystemParam
207206
pub struct Observer {
@@ -269,28 +268,44 @@ impl Observer {
269268
}
270269
}
271270

272-
/// Observe the given `entity`. This will cause the [`Observer`] to run whenever the [`Event`] is triggered
273-
/// for the `entity`.
271+
/// Observes the given `entity` (in addition to any entity already being observed).
272+
/// This will cause the [`Observer`] to run whenever the [`Event`] is triggered for the `entity`.
273+
/// Note that if this is called _after_ an [`Observer`] is spawned, it will produce no effects.
274274
pub fn with_entity(mut self, entity: Entity) -> Self {
275-
self.descriptor.entities.push(entity);
275+
self.watch_entity(entity);
276276
self
277277
}
278278

279-
/// Observe the given `entity`. This will cause the [`Observer`] to run whenever the [`Event`] is triggered
280-
/// for the `entity`.
279+
/// Observes the given `entities` (in addition to any entity already being observed).
280+
/// This will cause the [`Observer`] to run whenever the [`Event`] is triggered for any of these `entities`.
281+
/// Note that if this is called _after_ an [`Observer`] is spawned, it will produce no effects.
282+
pub fn with_entities<I: IntoIterator<Item = Entity>>(mut self, entities: I) -> Self {
283+
self.watch_entities(entities);
284+
self
285+
}
286+
287+
/// Observes the given `entity` (in addition to any entity already being observed).
288+
/// This will cause the [`Observer`] to run whenever the [`Event`] is triggered for the `entity`.
281289
/// Note that if this is called _after_ an [`Observer`] is spawned, it will produce no effects.
282290
pub fn watch_entity(&mut self, entity: Entity) {
283291
self.descriptor.entities.push(entity);
284292
}
285293

286-
/// Observe the given `component`. This will cause the [`Observer`] to run whenever the [`Event`] is triggered
294+
/// Observes the given `entity` (in addition to any entity already being observed).
295+
/// This will cause the [`Observer`] to run whenever the [`Event`] is triggered for any of these `entities`.
296+
/// Note that if this is called _after_ an [`Observer`] is spawned, it will produce no effects.
297+
pub fn watch_entities<I: IntoIterator<Item = Entity>>(&mut self, entities: I) {
298+
self.descriptor.entities.extend(entities);
299+
}
300+
301+
/// Observes the given `component`. This will cause the [`Observer`] to run whenever the [`Event`] is triggered
287302
/// with the given component target.
288303
pub fn with_component(mut self, component: ComponentId) -> Self {
289304
self.descriptor.components.push(component);
290305
self
291306
}
292307

293-
/// Observe the given `event_key`. This will cause the [`Observer`] to run whenever an event with the given [`EventKey`]
308+
/// Observes the given `event_key`. This will cause the [`Observer`] to run whenever an event with the given [`EventKey`]
294309
/// is triggered.
295310
/// # Safety
296311
/// The type of the `event_key` [`EventKey`] _must_ match the actual value
@@ -300,7 +315,7 @@ impl Observer {
300315
self
301316
}
302317

303-
/// Set the error handler to use for this observer.
318+
/// Sets the error handler to use for this observer.
304319
///
305320
/// See the [`error` module-level documentation](crate::error) for more information.
306321
pub fn with_error_handler(mut self, error_handler: fn(BevyError, ErrorContext)) -> Self {

crates/bevy_ecs/src/observer/mod.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1381,4 +1381,22 @@ mod tests {
13811381
assert_eq!(4, *counter.0.get(&a_id).unwrap());
13821382
assert_eq!(3, *counter.0.get(&b_id).unwrap());
13831383
}
1384+
1385+
#[test]
1386+
fn observer_watch_entities() {
1387+
let mut world = World::new();
1388+
world.init_resource::<Order>();
1389+
let entities = world
1390+
.spawn_batch(core::iter::repeat_n((), 4))
1391+
.collect::<Vec<_>>();
1392+
let observer = Observer::new(|_: On<EventA>, mut order: ResMut<Order>| {
1393+
order.observed("a");
1394+
});
1395+
world.spawn(observer.with_entities(entities.iter().copied().take(2)));
1396+
1397+
world.trigger_targets(EventA, [entities[0], entities[1]]);
1398+
assert_eq!(vec!["a", "a"], world.resource::<Order>().0);
1399+
world.trigger_targets(EventA, [entities[2], entities[3]]);
1400+
assert_eq!(vec!["a", "a"], world.resource::<Order>().0);
1401+
}
13841402
}

release-content/release-notes/observer_overhaul.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
title: Observer Overhaul
3-
authors: ["@Jondolf", "@alice-i-cecile", "@hukasu", "oscar-benderstone", "Zeophlite"]
4-
pull_requests: [19596, 19663, 19611, 19935]
3+
authors: ["@Jondolf", "@alice-i-cecile", "@hukasu", "oscar-benderstone", "Zeophlite", "gwafotapa"]
4+
pull_requests: [19596, 19663, 19611, 19935, 20274]
55
---
66

77
## Rename `Trigger` to `On`
@@ -50,3 +50,7 @@ this opens up the possibility for the debug tools to show more meaningful names
5050

5151
Internally, each `Event` type would generate a `Component` type, allowing us to use the corresponding `ComponentId` to track the event.
5252
We have newtyped this to `EventKey` to help separate these concerns.
53+
54+
## Watch multiple entities
55+
56+
To watch multiple entities with the same observer you previously had to call `Observer::with_entity` or `Observer::watch_entity` for each entity. New methods `Observer::with_entities` and `Observer::watch_entities` have been added for your convenience.

0 commit comments

Comments
 (0)