bevy_bundled_observers/lib.rs
1//! This crate provides the [`observers`] macro. See its documentation for further info.
2
3pub use bevy_ecs;
4use bevy_ecs::{component::HookContext, prelude::*, world::DeferredWorld};
5
6/// A macro for setting [`Observer`]s on an entity from within a [`Bundle`]. It is similar to the [`children`] macro, but for observers.
7///
8/// ```rust
9/// # use bevy::prelude::*;
10/// # use bevy_bundled_observers::observers;
11/// # #[derive(Event)] struct OnCollect;
12///
13/// fn coin() -> impl Bundle {
14/// (
15/// Name::new("Coin"),
16/// observers![|_: Trigger<OnCollect>| {
17/// info!("You collected a coin!");
18/// }],
19/// )
20/// }
21/// ```
22#[macro_export]
23macro_rules! observers {
24 [$($observer:expr),*$(,)?] => {
25 $crate::Observers(vec![$($crate::bevy_ecs::observer::Observer::new($observer)),*])
26 };
27}
28
29/// A component that sets observers on an entity when inserted. This is the underlying mechanism for the [`observers`] macro.
30///
31/// The component is immediately emptied and promptly removed after insertion.
32///
33/// The code example below shows what the [`observers`] macro expands to.
34///
35/// ```rust
36/// # use bevy::prelude::*;
37/// # use bevy_bundled_observers::Observers;
38/// # #[derive(Event)] struct OnCollect;
39///
40/// fn coin() -> impl Bundle {
41/// (
42/// Name::new("Coin"),
43/// Observers(vec![Observer::new(|_: Trigger<OnCollect>| {
44/// info!("You collected a coin!");
45/// })]),
46/// )
47/// }
48/// ```
49#[derive(Component)]
50#[component(on_insert = on_insert)]
51pub struct Observers(pub Vec<Observer>);
52
53fn on_insert(mut world: DeferredWorld, context: HookContext) {
54 let mut component: Mut<Observers> = world.get_mut(context.entity).unwrap();
55
56 let observers = core::mem::take(&mut component.0)
57 .into_iter()
58 .map(move |observer| observer.with_entity(context.entity));
59
60 let mut commands = world.commands();
61 commands.spawn_batch(observers);
62 commands.entity(context.entity).remove::<Observers>();
63}
64
65#[cfg(test)]
66mod test {
67 use bevy_ecs::prelude::*;
68
69 #[test]
70 fn test() {
71 #[derive(Event, Debug)]
72 struct OnFoo;
73
74 #[derive(Component, Debug, PartialEq, Eq)]
75 struct Bar(i32);
76
77 let mut world = World::new();
78
79 let entity = world
80 .spawn((
81 Bar(0),
82 observers![|trigger: Trigger<OnFoo>, mut query: Query<&mut Bar>| {
83 query.get_mut(trigger.target()).unwrap().0 += 1;
84 }],
85 ))
86 .id();
87
88 world.trigger_targets(OnFoo, entity);
89
90 assert_eq!(world.get::<Bar>(entity), Some(&Bar(1)));
91 }
92}