avian2d/collision/
collision_events.rs

1//! Collision events for detecting when colliders start or stop touching.
2//!
3//! Avian provides two collision event types:
4//!
5//! - [`CollisionStart`]: Triggered when two colliders start touching.
6//! - [`CollisionEnd`]: Triggered when two colliders stop touching.
7//!
8//! Depending on your use case, you may want to read them as [`Message`]s with a [`MessageReader`],
9//! or observe them as [`Event`]s with an [observer](Observer). Avian supports both options.
10//!
11//! # Reading Collision Events
12//!
13//! To enable collision events for a collider entity, add the [`CollisionEventsEnabled`] component.
14//!
15//! ```
16#![cfg_attr(feature = "2d", doc = "use avian2d::prelude::*;")]
17#![cfg_attr(feature = "3d", doc = "use avian3d::prelude::*;")]
18//! use bevy::prelude::*;
19//!
20//! #[derive(Component)]
21//! struct PressurePlate;
22//!
23//! fn setup_pressure_plates(mut commands: Commands) {
24//!     commands.spawn((
25//!         PressurePlate,
26#![cfg_attr(feature = "2d", doc = "        Collider::rectangle(1.0, 1.0),")]
27#![cfg_attr(feature = "3d", doc = "        Collider::cuboid(1.0, 0.1, 1.0),")]
28//!         Sensor,
29//!         // Enable collision events for this entity.
30//!         CollisionEventsEnabled,
31//!     ));
32//! }
33//! ```
34//!
35//! The [`CollisionStart`] and [`CollisionEnd`] events will now be both written as a [`Message`]
36//! and triggered as an [`Event`] when the entity starts or stops touching another collider.
37//! It is up to you to decide which event processing method is best suited for your use case.
38//!
39//! ## Collision `Message`
40//!
41//! Reading collision events as [`Message`]s with a [`MessageReader`] can be very efficient
42//! for processing large numbers of collisions between pairs of entities, such as for detecting
43//! bullet hits or playing impact sounds when two objects collide.
44//!
45//! The events are only written if one of the entities has the [`CollisionEventsEnabled`] component.
46//!
47//! ```
48#![cfg_attr(feature = "2d", doc = "# use avian2d::prelude::*;")]
49#![cfg_attr(feature = "3d", doc = "# use avian3d::prelude::*;")]
50//! # use bevy::prelude::*;
51//! #
52//! fn print_started_collisions(mut collision_reader: MessageReader<CollisionStart>) {
53//!     for event in collision_reader.read() {
54//!         println!("{} and {} started colliding", event.collider1, event.collider2);
55//!     }
56//! }
57//! ```
58//!
59//! ## Collision `Event`
60//!
61//! Observing collision events as [`Event`]s with an [observer](Observer) can be very useful
62//! for entity-specific collision scenarios, such as for detecting when a player steps on
63//! a pressure plate or enters a trigger volume.
64//!
65//! The events are only triggered if the target entity has the [`CollisionEventsEnabled`] component.
66//!
67//! ```
68#![cfg_attr(feature = "2d", doc = "# use avian2d::prelude::*;")]
69#![cfg_attr(feature = "3d", doc = "# use avian3d::prelude::*;")]
70//! # use bevy::prelude::*;
71//! #
72//! # #[derive(Component)]
73//! # struct Player;
74//! #
75//! # #[derive(Component)]
76//! # struct PressurePlate;
77//! #
78//! fn setup_pressure_plates(mut commands: Commands) {
79//!     commands.spawn((
80//!         PressurePlate,
81#![cfg_attr(feature = "2d", doc = "        Collider::rectangle(1.0, 1.0),")]
82#![cfg_attr(feature = "3d", doc = "        Collider::cuboid(1.0, 0.1, 1.0),")]
83//!         Sensor,
84//!         // Enable collision events for this entity.
85//!         CollisionEventsEnabled,
86//!     ))
87//!     .observe(on_player_stepped_on_plate);
88//! }
89//!
90//! fn on_player_stepped_on_plate(event: On<CollisionStart>, player_query: Query<&Player>) {
91//!     // `colider1` and `body1` refer to the event target and its body.
92//!     // `collider2` and `body2` refer to the other collider and its body.
93//!     let pressure_plate = event.collider1;
94//!     let other_entity = event.collider2;
95//!
96//!     if player_query.contains(other_entity) {
97//!         println!("Player {other_entity} stepped on pressure plate {pressure_plate}");
98//!     }
99//! }
100//! ```
101
102use bevy::prelude::*;
103
104/// A [collision event](self) that is triggered when two colliders start touching.
105///
106/// The event can be read using a [`MessageReader`] or observed using an [observer](Observer).
107/// It is only triggered for entities with the [`CollisionEventsEnabled`] component.
108///
109/// # Example
110///
111/// Below is an example of observing the [`CollisionStart`] event using an [observer](Observer).
112///
113/// ```
114#[cfg_attr(feature = "2d", doc = "use avian2d::prelude::*;")]
115#[cfg_attr(feature = "3d", doc = "use avian3d::prelude::*;")]
116/// use bevy::prelude::*;
117///
118/// #[derive(Component)]
119/// struct Player;
120///
121/// #[derive(Component)]
122/// struct PressurePlate;
123///
124/// fn setup_pressure_plates(mut commands: Commands) {
125///     commands.spawn((
126///         PressurePlate,
127#[cfg_attr(feature = "2d", doc = "        Collider::rectangle(1.0, 1.0),")]
128#[cfg_attr(feature = "3d", doc = "        Collider::cuboid(1.0, 0.1, 1.0),")]
129///         Sensor,
130///         // Enable collision events for this entity.
131///         CollisionEventsEnabled,
132///     ))
133///     .observe(on_player_stepped_on_plate);
134/// }
135///
136/// fn on_player_stepped_on_plate(event: On<CollisionStart>, player_query: Query<&Player>) {
137///     // `colider1` and `body1` refer to the event target and its body.
138///     // `collider2` and `body2` refer to the other collider and its body.
139///     let pressure_plate = event.collider1;
140///     let other_entity = event.collider2;
141///
142///     if player_query.contains(other_entity) {
143///         println!("Player {other_entity} stepped on pressure plate {pressure_plate}");
144///     }
145/// }
146/// ```
147///
148/// The event can also be read as a [`Message`] using a [`MessageReader`].
149/// This can be more efficient for processing large numbers of collisions.
150///
151/// ```
152#[cfg_attr(feature = "2d", doc = "# use avian2d::prelude::*;")]
153#[cfg_attr(feature = "3d", doc = "# use avian3d::prelude::*;")]
154/// # use bevy::prelude::*;
155/// #
156/// fn print_started_collisions(mut collision_reader: MessageReader<CollisionStart>) {
157///     for event in collision_reader.read() {
158///         println!("{} and {} started colliding", event.collider1, event.collider2);
159///     }
160/// }
161/// ```
162///
163/// # Scheduling
164///
165/// The [`CollisionStart`] event is triggered after the physics step in the [`CollisionEventSystems`]
166/// system set. At this point, the solver has already run and contact impulses have been updated.
167///
168/// [`CollisionEventSystems`]: super::narrow_phase::CollisionEventSystems
169#[derive(EntityEvent, Message, Clone, Copy, Debug, PartialEq)]
170#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
171pub struct CollisionStart {
172    /// The entity of the collider that started colliding with [`collider2`](Self::collider2).
173    ///
174    /// For observers watching this event as an [`EntityEvent`], this is the target entity.
175    #[event_target]
176    pub collider1: Entity,
177    /// The entity of the collider that started colliding with [`collider1`](Self::collider1).
178    pub collider2: Entity,
179    /// The rigid body that [`collider1`](Self::collider1) is attached to.
180    ///
181    /// If the collider is not attached to a rigid body, this will be `None`.
182    pub body1: Option<Entity>,
183    /// The rigid body that [`collider2`](Self::collider2) is attached to.
184    ///
185    /// If the collider is not attached to a rigid body, this will be `None`.
186    pub body2: Option<Entity>,
187    // TODO: Flags to expose the reason for the event, among other things.
188    // flags: CollisionStartFlags,
189}
190
191/// A deprecated alias for [`CollisionStart`].
192#[deprecated(since = "0.4.0", note = "Renamed to `CollisionStart`")]
193pub type OnCollisionStart = CollisionStart;
194
195/// A [collision event](self) that is triggered when two colliders stop touching.
196///
197/// The event can be read using a [`MessageReader`] or observed using an [observer](Observer).
198/// It is only triggered for entities with the [`CollisionEventsEnabled`] component.
199///
200/// # Example
201///
202/// Below is an example of observing the [`CollisionEnd`] event using an [observer](Observer).
203///
204/// ```
205#[cfg_attr(feature = "2d", doc = "use avian2d::prelude::*;")]
206#[cfg_attr(feature = "3d", doc = "use avian3d::prelude::*;")]
207/// use bevy::prelude::*;
208///
209/// #[derive(Component)]
210/// struct Player;
211///
212/// #[derive(Component)]
213/// struct PressurePlate;
214///
215/// fn setup_pressure_plates(mut commands: Commands) {
216///     commands.spawn((
217///         PressurePlate,
218#[cfg_attr(feature = "2d", doc = "        Collider::rectangle(1.0, 1.0),")]
219#[cfg_attr(feature = "3d", doc = "        Collider::cuboid(1.0, 0.1, 1.0),")]
220///         Sensor,
221///         // Enable collision events for this entity.
222///         CollisionEventsEnabled,
223///     ))
224///     .observe(on_player_stepped_off_plate);
225/// }
226///
227/// fn on_player_stepped_off_plate(event: On<CollisionEnd>, player_query: Query<&Player>) {
228///     // `colider1` and `body1` refer to the event target and its body.
229///     // `collider2` and `body2` refer to the other collider and its body.
230///     let pressure_plate = event.collider1;
231///     let other_entity = event.collider2;
232///
233///     if player_query.contains(other_entity) {
234///         println!("Player {other_entity} stepped off pressure plate {pressure_plate}");
235///     }
236/// }
237/// ```
238///
239/// The event can also be read as a [`Message`] using a [`MessageReader`].
240/// This can be more efficient for processing large numbers of collisions.
241///
242/// ```
243#[cfg_attr(feature = "2d", doc = "# use avian2d::prelude::*;")]
244#[cfg_attr(feature = "3d", doc = "# use avian3d::prelude::*;")]
245/// # use bevy::prelude::*;
246/// #
247/// fn print_ended_collisions(mut collision_reader: MessageReader<CollisionEnd>) {
248///     for event in collision_reader.read() {
249///         println!("{} and {} stopped colliding", event.collider1, event.collider2);
250///     }
251/// }
252/// ```
253///
254/// # Scheduling
255///
256/// The [`CollisionEnd`] event is triggered after the physics step in the [`CollisionEventSystems`]
257/// system set. At this point, the solver has already run and contact impulses have been updated.
258///
259/// Note that if one of the colliders was removed or the bounding boxes of the colliders stopped
260/// overlapping, the [`ContactPair`] between the entities was also removed, and the contact data
261/// will not be available through [`Collisions`].
262///
263/// [`CollisionEventSystems`]: super::narrow_phase::CollisionEventSystems
264/// [`ContactPair`]: super::ContactPair
265/// [`Collisions`]: super::Collisions
266#[derive(EntityEvent, Message, Clone, Copy, Debug, PartialEq)]
267#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
268pub struct CollisionEnd {
269    /// The entity of the collider that stopped colliding with [`collider2`](Self::collider2).
270    ///
271    /// For observers watching this event as an [`EntityEvent`], this is the target entity.
272    #[event_target]
273    pub collider1: Entity,
274    /// The entity of the collider that stopped colliding with [`collider1`](Self::collider1).
275    pub collider2: Entity,
276    /// The rigid body that [`collider1`](Self::collider1) is attached to.
277    ///
278    /// If the collider is not attached to a rigid body, this will be `None`.
279    pub body1: Option<Entity>,
280    /// The rigid body that [`collider2`](Self::collider2) is attached to.
281    ///
282    /// If the collider is not attached to a rigid body, this will be `None`.
283    pub body2: Option<Entity>,
284    // TODO: Flags to expose the reason for the event, among other things.
285    // flags: CollisionEndFlags,
286}
287
288/// A deprecated alias for [`CollisionEnd`].
289#[deprecated(since = "0.4.0", note = "Renamed to `CollisionEnd`")]
290pub type OnCollisionEnd = CollisionEnd;
291
292/// A marker component that enables [collision events](self) for an entity.
293#[derive(Component, Clone, Copy, Debug, Default, Reflect)]
294#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
295#[cfg_attr(feature = "serialize", reflect(Serialize, Deserialize))]
296#[reflect(Component, Debug)]
297pub struct CollisionEventsEnabled;