|
1 | | -//! [`CollisionStarted`] and [`CollisionEnded`] events. |
| 1 | +//! Collision events for detecting when colliders start or stop touching. |
2 | 2 | //! |
3 | | -//! Collision events are only sent if one of the entities has the [`CollisionEventsEnabled`] component. |
| 3 | +//! Depending on your use case, you may want to use either buffered events read |
| 4 | +//! using an [`EventReader`] or observable events triggered for specific entities. |
| 5 | +//! Avian provides both options using separate event types. |
4 | 6 | //! |
5 | | -//! You can listen to these events with normal event readers: |
| 7 | +//! Note that collision events are only sent or triggered for entities that have |
| 8 | +//! the [`CollisionEventsEnabled`] component. |
6 | 9 | //! |
7 | | -//! ```no_run |
| 10 | +//! # Buffered Events |
| 11 | +//! |
| 12 | +//! Avian provides two different buffered collision event types: |
| 13 | +//! |
| 14 | +//! - [`CollisionStarted`] |
| 15 | +//! - [`CollisionEnded`] |
| 16 | +//! |
| 17 | +//! These events are sent when two colliders start or stop touching, and can be read |
| 18 | +//! using an [`EventReader`]. This can be useful for efficiently processing large numbers |
| 19 | +//! of collision events between pairs of entities, such as for detecting bullet hits |
| 20 | +//! or playing impact sounds when two objects collide. |
| 21 | +//! |
| 22 | +//! The events are only sent if one of the entities has the [`CollisionEventsEnabled`] component. |
| 23 | +//! |
| 24 | +//! ``` |
8 | 25 | #![cfg_attr(feature = "2d", doc = "use avian2d::prelude::*;")] |
9 | 26 | #![cfg_attr(feature = "3d", doc = "use avian3d::prelude::*;")] |
10 | 27 | //! use bevy::prelude::*; |
11 | 28 | //! |
12 | | -//! fn main() { |
13 | | -//! App::new() |
14 | | -//! .add_plugins((DefaultPlugins, PhysicsPlugins::default())) |
15 | | -//! // ... |
16 | | -//! .add_systems(Update, print_collisions) |
17 | | -//! .run(); |
18 | | -//! } |
19 | | -//! |
20 | | -//! fn print_collisions(mut collision_event_reader: EventReader<CollisionStarted>) { |
| 29 | +//! fn print_started_collisions(mut collision_event_reader: EventReader<CollisionStarted>) { |
21 | 30 | //! for CollisionStarted(entity1, entity2) in collision_event_reader.read() { |
22 | | -//! println!("Entities {entity1} and {entity2} are colliding"); |
| 31 | +//! println!("{entity1} and {entity2} started colliding"); |
23 | 32 | //! } |
24 | 33 | //! } |
25 | 34 | //! ``` |
26 | 35 | //! |
27 | | -//! Collision events that use observers are not yet supported. |
| 36 | +//! # Observable Events |
| 37 | +//! |
| 38 | +//! Avian provides two observable collision event types: |
| 39 | +//! |
| 40 | +//! - [`OnCollisionStart`] |
| 41 | +//! - [`OnCollisionEnd`] |
| 42 | +//! |
| 43 | +//! These events are triggered for [observers](Observer) when two colliders start or stop touching. |
| 44 | +//! This makes them good for entity-specific collision scenarios, such as for detecting when a player |
| 45 | +//! steps on a pressure plate or enters a trigger volume. |
| 46 | +//! |
| 47 | +//! The events are only triggered if the target entity has the [`CollisionEventsEnabled`] component. |
| 48 | +//! |
| 49 | +//! ``` |
| 50 | +#![cfg_attr(feature = "2d", doc = "use avian2d::prelude::*;")] |
| 51 | +#![cfg_attr(feature = "3d", doc = "use avian3d::prelude::*;")] |
| 52 | +//! use bevy::prelude::*; |
| 53 | +//! |
| 54 | +//! #[derive(Component)] |
| 55 | +//! struct Player; |
| 56 | +//! |
| 57 | +//! #[derive(Component)] |
| 58 | +//! struct PressurePlate; |
| 59 | +//! |
| 60 | +//! fn setup_pressure_plates(mut commands: Commands) { |
| 61 | +//! commands.spawn(( |
| 62 | +//! PressurePlate, |
| 63 | +#![cfg_attr(feature = "2d", doc = " Collider::rectangle(1.0, 1.0),")] |
| 64 | +#![cfg_attr(feature = "3d", doc = " Collider::cuboid(1.0, 0.1, 1.0),")] |
| 65 | +//! Sensor, |
| 66 | +//! // Enable collision events for this entity. |
| 67 | +//! CollisionEventsEnabled, |
| 68 | +//! )) |
| 69 | +//! .observe(|trigger: Trigger<OnCollisionStart>, player_query: Query<&Player>| { |
| 70 | +//! let pressure_plate = trigger.target(); |
| 71 | +//! let other_entity = trigger.0; |
| 72 | +//! if player_query.contains(other_entity) { |
| 73 | +//! println!("Player {other_entity} stepped on pressure plate {pressure_plate}"); |
| 74 | +//! } |
| 75 | +//! }); |
| 76 | +//! } |
| 77 | +//! ``` |
28 | 78 |
|
29 | 79 | use bevy::prelude::*; |
30 | 80 |
|
31 | | -/// A [collision event](super#collision-events) that is sent when two colliders start touching. |
| 81 | +/// A buffered [collision event](super#collision-events) that is sent when two colliders start touching. |
32 | 82 | /// |
33 | 83 | /// The event is only sent if one of the entities has the [`CollisionEventsEnabled`] component. |
34 | 84 | /// |
| 85 | +/// Unlike [`OnCollisionStart`], this event is *not* triggered for observers. |
| 86 | +/// Instead, you must use an [`EventReader`] to read the event in a system. |
| 87 | +/// This makes it good for efficiently processing large numbers of collision events |
| 88 | +/// between pairs of entities. |
| 89 | +/// |
35 | 90 | /// # Example |
36 | 91 | /// |
37 | | -/// ```no_run |
| 92 | +/// ``` |
38 | 93 | #[cfg_attr(feature = "2d", doc = "use avian2d::prelude::*;")] |
39 | 94 | #[cfg_attr(feature = "3d", doc = "use avian3d::prelude::*;")] |
40 | 95 | /// use bevy::prelude::*; |
41 | 96 | /// |
42 | | -/// fn main() { |
43 | | -/// App::new() |
44 | | -/// .add_plugins((DefaultPlugins, PhysicsPlugins::default())) |
45 | | -/// // ... |
46 | | -/// .add_systems(Update, print_started_collisions) |
47 | | -/// .run(); |
48 | | -/// } |
49 | | -/// |
50 | 97 | /// fn print_started_collisions(mut collision_event_reader: EventReader<CollisionStarted>) { |
51 | 98 | /// for CollisionStarted(entity1, entity2) in collision_event_reader.read() { |
52 | | -/// println!( |
53 | | -/// "Entities {} and {} started colliding", |
54 | | -/// entity1, |
55 | | -/// entity2, |
56 | | -/// ); |
| 99 | +/// println!("{entity1} and {entity2} started colliding"); |
57 | 100 | /// } |
58 | 101 | /// } |
59 | 102 | /// ``` |
60 | | -#[derive(Event, Clone, Debug, PartialEq)] |
| 103 | +/// |
| 104 | +/// # Scheduling |
| 105 | +/// |
| 106 | +/// The [`CollisionStarted`] event is sent in the [`NarrowPhaseSet::Update`] system set, |
| 107 | +/// but can be read at any time. |
| 108 | +/// |
| 109 | +/// [`NarrowPhaseSet::Update`]: super::narrow_phase::NarrowPhaseSet::Update |
| 110 | +#[derive(Event, Clone, Copy, Debug, PartialEq)] |
61 | 111 | #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] |
62 | 112 | pub struct CollisionStarted(pub Entity, pub Entity); |
63 | 113 |
|
64 | | -/// A [collision event](super#collision-events) that is sent when two colliders stop touching. |
| 114 | +/// A buffered [collision event](super#collision-events) that is sent when two colliders stop touching. |
65 | 115 | /// |
66 | 116 | /// The event is only sent if one of the entities has the [`CollisionEventsEnabled`] component. |
67 | 117 | /// |
| 118 | +/// Unlike [`OnCollisionEnd`], this event is *not* triggered for observers. |
| 119 | +/// Instead, you must use an [`EventReader`] to read the event in a system. |
| 120 | +/// This makes it good for efficiently processing large numbers of collision events |
| 121 | +/// between pairs of entities. |
| 122 | +/// |
68 | 123 | /// # Example |
69 | 124 | /// |
70 | | -/// ```no_run |
| 125 | +/// ``` |
71 | 126 | #[cfg_attr(feature = "2d", doc = "use avian2d::prelude::*;")] |
72 | 127 | #[cfg_attr(feature = "3d", doc = "use avian3d::prelude::*;")] |
73 | 128 | /// use bevy::prelude::*; |
74 | 129 | /// |
75 | | -/// fn main() { |
76 | | -/// App::new() |
77 | | -/// .add_plugins((DefaultPlugins, PhysicsPlugins::default())) |
78 | | -/// // ... |
79 | | -/// .add_systems(Update, print_ended_collisions) |
80 | | -/// .run(); |
81 | | -/// } |
82 | | -/// |
83 | 130 | /// fn print_ended_collisions(mut collision_event_reader: EventReader<CollisionEnded>) { |
84 | 131 | /// for CollisionEnded(entity1, entity2) in collision_event_reader.read() { |
85 | | -/// println!( |
86 | | -/// "Entities {} and {} stopped colliding", |
87 | | -/// entity1, |
88 | | -/// entity2, |
89 | | -/// ); |
| 132 | +/// println!("{entity1} and {entity2} stopped colliding"); |
90 | 133 | /// } |
91 | 134 | /// } |
92 | 135 | /// ``` |
93 | | -#[derive(Event, Clone, Debug, PartialEq)] |
| 136 | +/// |
| 137 | +/// # Scheduling |
| 138 | +/// |
| 139 | +/// The [`CollisionEnded`] event is sent in the [`NarrowPhaseSet::Update`] system set, |
| 140 | +/// but can be read at any time. |
| 141 | +/// |
| 142 | +/// Note that if one of the colliders was removed or the bounding boxes of the colliders stopped |
| 143 | +/// overlapping, the [`ContactPair`] between the entities was also removed, and the contact data |
| 144 | +/// will not be available through [`Collisions`]. |
| 145 | +/// |
| 146 | +/// [`NarrowPhaseSet::Update`]: super::narrow_phase::NarrowPhaseSet::Update |
| 147 | +/// [`ContactPair`]: super::ContactPair |
| 148 | +/// [`Collisions`]: super::Collisions |
| 149 | +#[derive(Event, Clone, Copy, Debug, PartialEq)] |
94 | 150 | #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] |
95 | 151 | pub struct CollisionEnded(pub Entity, pub Entity); |
96 | 152 |
|
97 | | -/// A marker component that enables [`CollisionStarted`] and [`CollisionEnded`] events for an entity. |
| 153 | +/// A [collision event](super#collision-events) that is triggered for [observers](Observer) |
| 154 | +/// when two colliders start touching. |
| 155 | +/// |
| 156 | +/// The event is only triggered if the target entity has the [`CollisionEventsEnabled`] component. |
| 157 | +/// |
| 158 | +/// Unlike [`CollisionStarted`], this event can *not* be read using an [`EventReader`]. |
| 159 | +/// Instead, you must use an [observer](Observer). This makes it good for entity-specific |
| 160 | +/// collision listeners. |
| 161 | +/// |
| 162 | +/// # Example |
| 163 | +/// |
| 164 | +/// ``` |
| 165 | +#[cfg_attr(feature = "2d", doc = "use avian2d::prelude::*;")] |
| 166 | +#[cfg_attr(feature = "3d", doc = "use avian3d::prelude::*;")] |
| 167 | +/// use bevy::prelude::*; |
| 168 | +/// |
| 169 | +/// #[derive(Component)] |
| 170 | +/// struct Player; |
| 171 | +/// |
| 172 | +/// #[derive(Component)] |
| 173 | +/// struct PressurePlate; |
| 174 | +/// |
| 175 | +/// fn setup_pressure_plates(mut commands: Commands) { |
| 176 | +/// commands.spawn(( |
| 177 | +/// PressurePlate, |
| 178 | +#[cfg_attr(feature = "2d", doc = " Collider::rectangle(1.0, 1.0),")] |
| 179 | +#[cfg_attr(feature = "3d", doc = " Collider::cuboid(1.0, 0.1, 1.0),")] |
| 180 | +/// Sensor, |
| 181 | +/// // Enable collision events for this entity. |
| 182 | +/// CollisionEventsEnabled, |
| 183 | +/// )) |
| 184 | +/// .observe(|trigger: Trigger<OnCollisionStart>, player_query: Query<&Player>| { |
| 185 | +/// let pressure_plate = trigger.target(); |
| 186 | +/// let other_entity = trigger.0; |
| 187 | +/// if player_query.contains(other_entity) { |
| 188 | +/// println!("Player {other_entity} stepped on pressure plate {pressure_plate}"); |
| 189 | +/// } |
| 190 | +/// }); |
| 191 | +/// } |
| 192 | +/// ``` |
| 193 | +/// |
| 194 | +/// # Scheduling |
| 195 | +/// |
| 196 | +/// The [`OnCollisionStart`] event is triggered after the physics step in the [`CollisionEventSystems`] |
| 197 | +/// system set. At this point, the solver has already run and contact impulses have been updated. |
| 198 | +/// |
| 199 | +/// [`CollisionEventSystems`]: super::narrow_phase::CollisionEventSystems |
| 200 | +#[derive(Event, Clone, Copy, Debug, PartialEq)] |
| 201 | +#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] |
| 202 | +pub struct OnCollisionStart(pub Entity); |
| 203 | + |
| 204 | +/// A [collision event](super#collision-events) that is triggered for [observers](Observer) |
| 205 | +/// when two colliders stop touching. |
| 206 | +/// |
| 207 | +/// The event is only triggered if the target entity has the [`CollisionEventsEnabled`] component. |
| 208 | +/// |
| 209 | +/// Unlike [`CollisionEnded`], this event can *not* be read using an [`EventReader`]. |
| 210 | +/// Instead, you must use an [observer](Observer). This makes it good for entity-specific |
| 211 | +/// collision listeners. |
| 212 | +/// |
| 213 | +/// # Example |
| 214 | +/// |
| 215 | +/// ``` |
| 216 | +#[cfg_attr(feature = "2d", doc = "use avian2d::prelude::*;")] |
| 217 | +#[cfg_attr(feature = "3d", doc = "use avian3d::prelude::*;")] |
| 218 | +/// use bevy::prelude::*; |
| 219 | +/// |
| 220 | +/// #[derive(Component)] |
| 221 | +/// struct Player; |
| 222 | +/// |
| 223 | +/// #[derive(Component)] |
| 224 | +/// struct PressurePlate; |
| 225 | +/// |
| 226 | +/// fn setup_pressure_plates(mut commands: Commands) { |
| 227 | +/// commands.spawn(( |
| 228 | +/// PressurePlate, |
| 229 | +#[cfg_attr(feature = "2d", doc = " Collider::rectangle(1.0, 1.0),")] |
| 230 | +#[cfg_attr(feature = "3d", doc = " Collider::cuboid(1.0, 0.1, 1.0),")] |
| 231 | +/// Sensor, |
| 232 | +/// // Enable collision events for this entity. |
| 233 | +/// CollisionEventsEnabled, |
| 234 | +/// )) |
| 235 | +/// .observe(|trigger: Trigger<OnCollisionEnd>, player_query: Query<&Player>| { |
| 236 | +/// let pressure_plate = trigger.target(); |
| 237 | +/// let other_entity = trigger.0; |
| 238 | +/// if player_query.contains(other_entity) { |
| 239 | +/// println!("Player {other_entity} stepped off of pressure plate {pressure_plate}"); |
| 240 | +/// } |
| 241 | +/// }); |
| 242 | +/// } |
| 243 | +/// ``` |
| 244 | +/// |
| 245 | +/// # Scheduling |
| 246 | +/// |
| 247 | +/// The [`OnCollisionEnd`] event is triggered after the physics step in the [`CollisionEventSystems`] |
| 248 | +/// system set. At this point, the solver has already run and contact impulses have been updated. |
| 249 | +/// |
| 250 | +/// Note that if one of the colliders was removed or the bounding boxes of the colliders stopped |
| 251 | +/// overlapping, the [`ContactPair`] between the entities was also removed, and the contact data |
| 252 | +/// will not be available through [`Collisions`]. |
| 253 | +/// |
| 254 | +/// [`CollisionEventSystems`]: super::narrow_phase::CollisionEventSystems |
| 255 | +/// [`ContactPair`]: super::ContactPair |
| 256 | +/// [`Collisions`]: super::Collisions |
| 257 | +#[derive(Event, Clone, Copy, Debug, PartialEq)] |
| 258 | +#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] |
| 259 | +pub struct OnCollisionEnd(pub Entity); |
| 260 | + |
| 261 | +/// A marker component that enables [collision events](self) for an entity. |
| 262 | +/// |
| 263 | +/// This enables both the buffered [`CollisionStarted`] and [`CollisionEnded`] events, |
| 264 | +/// as well as the observable [`OnCollisionStart`] and [`OnCollisionEnd`] events. |
98 | 265 | #[derive(Component, Clone, Copy, Debug, Default, Reflect)] |
99 | 266 | #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] |
100 | 267 | #[cfg_attr(feature = "serialize", reflect(Serialize, Deserialize))] |
|
0 commit comments