avian2d/collision/collider/mod.rs
1//! Components, traits, and plugins related to collider functionality.
2
3use crate::prelude::*;
4use bevy::{
5 ecs::{
6 component::Mutable,
7 entity::{EntityMapper, MapEntities, hash_set::EntityHashSet},
8 system::{ReadOnlySystemParam, SystemParam, SystemParamItem},
9 },
10 prelude::*,
11};
12use derive_more::From;
13
14mod backend;
15
16pub use backend::{ColliderBackendPlugin, ColliderMarker};
17
18#[cfg(all(feature = "collider-from-mesh", feature = "default-collider"))]
19mod cache;
20#[cfg(all(feature = "collider-from-mesh", feature = "default-collider"))]
21pub use cache::ColliderCachePlugin;
22pub mod collider_hierarchy;
23pub mod collider_transform;
24
25mod layers;
26pub use layers::*;
27
28/// The default [`Collider`] that uses Parry.
29#[cfg(all(
30 feature = "default-collider",
31 any(feature = "parry-f32", feature = "parry-f64")
32))]
33mod parry;
34#[cfg(all(
35 feature = "default-collider",
36 any(feature = "parry-f32", feature = "parry-f64")
37))]
38pub use parry::*;
39
40#[cfg(feature = "default-collider")]
41mod constructor;
42#[cfg(feature = "default-collider")]
43pub use constructor::{
44 ColliderConstructor, ColliderConstructorHierarchy, ColliderConstructorHierarchyConfig,
45 ColliderConstructorHierarchyReady, ColliderConstructorReady,
46};
47
48/// A trait for creating colliders from other types.
49pub trait IntoCollider<C: AnyCollider> {
50 /// Creates a collider from `self`.
51 fn collider(&self) -> C;
52}
53
54/// Context necessary to calculate [`ColliderAabb`]s for an [`AnyCollider`]
55#[derive(Deref)]
56pub struct AabbContext<'a, 'w, 's, T: ReadOnlySystemParam> {
57 /// The entity for which the aabb is being calculated
58 pub entity: Entity,
59 #[deref]
60 item: &'a SystemParamItem<'w, 's, T>,
61}
62
63impl<T: ReadOnlySystemParam> Clone for AabbContext<'_, '_, '_, T> {
64 fn clone(&self) -> Self {
65 Self {
66 entity: self.entity,
67 item: self.item,
68 }
69 }
70}
71
72impl<'a, 'w, 's, T: ReadOnlySystemParam> AabbContext<'a, 'w, 's, T> {
73 /// Construct an [`AabbContext`]
74 pub fn new(entity: Entity, item: &'a <T as SystemParam>::Item<'w, 's>) -> Self {
75 Self { entity, item }
76 }
77}
78
79impl AabbContext<'_, '_, '_, ()> {
80 fn fake() -> Self {
81 Self {
82 entity: Entity::PLACEHOLDER,
83 item: &(),
84 }
85 }
86}
87
88/// Context necessary to calculate [`ContactManifold`]s for a set of [`AnyCollider`]
89#[derive(Deref)]
90pub struct ContactManifoldContext<'a, 'w, 's, T: ReadOnlySystemParam> {
91 /// The first collider entity involved in the contact.
92 pub entity1: Entity,
93 /// The second collider entity involved in the contact.
94 pub entity2: Entity,
95 #[deref]
96 item: &'a SystemParamItem<'w, 's, T>,
97}
98
99impl<'a, 'w, 's, T: ReadOnlySystemParam> ContactManifoldContext<'a, 'w, 's, T> {
100 /// Construct a [`ContactManifoldContext`]
101 pub fn new(
102 entity1: Entity,
103 entity2: Entity,
104 item: &'a <T as SystemParam>::Item<'w, 's>,
105 ) -> Self {
106 Self {
107 entity1,
108 entity2,
109 item,
110 }
111 }
112}
113
114impl ContactManifoldContext<'_, '_, '_, ()> {
115 fn fake() -> Self {
116 Self {
117 entity1: Entity::PLACEHOLDER,
118 entity2: Entity::PLACEHOLDER,
119 item: &(),
120 }
121 }
122}
123
124/// A trait that generalizes over colliders. Implementing this trait
125/// allows colliders to be used with the physics engine.
126pub trait AnyCollider: Component<Mutability = Mutable> + ComputeMassProperties {
127 /// A type providing additional context for collider operations.
128 ///
129 /// `Context` allows you to access an arbitrary [`ReadOnlySystemParam`] on
130 /// the world, for context-sensitive behavior in collider operations. You
131 /// can use this to query components on the collider entity, or get any
132 /// other necessary context from the world.
133 ///
134 /// # Example
135 ///
136 /// ```
137 #[cfg_attr(
138 feature = "2d",
139 doc = "# use avian2d::{prelude::*, math::{Vector, Scalar}};"
140 )]
141 #[cfg_attr(
142 feature = "3d",
143 doc = "# use avian3d::{prelude::*, math::{Vector, Scalar}};"
144 )]
145 /// # use bevy::prelude::*;
146 /// # use bevy::ecs::system::{SystemParam, lifetimeless::{SRes, SQuery}};
147 /// #
148 /// #[derive(Component)]
149 /// pub struct VoxelCollider;
150 ///
151 /// #[derive(Component)]
152 /// pub struct VoxelData {
153 /// // collider voxel data...
154 /// }
155 ///
156 /// # impl ComputeMassProperties2d for VoxelCollider {
157 /// # fn mass(&self, density: f32) -> f32 {0.}
158 /// # fn unit_angular_inertia(&self) -> f32 { 0.}
159 /// # fn center_of_mass(&self) -> Vec2 { Vec2::ZERO }
160 /// # }
161 /// #
162 /// # impl ComputeMassProperties3d for VoxelCollider {
163 /// # fn mass(&self, density: f32) -> f32 {0.}
164 /// # fn unit_principal_angular_inertia(&self) -> Vec3 { Vec3::ZERO }
165 /// # fn center_of_mass(&self) -> Vec3 { Vec3::ZERO }
166 /// # }
167 /// #
168 /// impl AnyCollider for VoxelCollider {
169 /// type Context = (
170 /// // you can query extra components here
171 /// SQuery<&'static VoxelData>,
172 /// // or put any other read-only system param here
173 /// SRes<Time>,
174 /// );
175 ///
176 /// # fn aabb_with_context(
177 /// # &self,
178 /// # _: Vector,
179 /// # _: impl Into<Rotation>,
180 /// # _: AabbContext<Self::Context>,
181 /// # ) -> ColliderAabb { unimplemented!() }
182 /// #
183 /// fn contact_manifolds_with_context(
184 /// &self,
185 /// other: &Self,
186 /// position1: Vector,
187 /// rotation1: impl Into<Rotation>,
188 /// position2: Vector,
189 /// rotation2: impl Into<Rotation>,
190 /// prediction_distance: Scalar,
191 /// manifolds: &mut Vec<ContactManifold>,
192 /// context: ContactManifoldContext<Self::Context>,
193 /// ) {
194 /// let [voxels1, voxels2] = context.0.get_many([context.entity1, context.entity2])
195 /// .expect("our own `VoxelCollider` entities should have `VoxelData`");
196 /// let elapsed = context.1.elapsed();
197 /// // do some computation...
198 /// # unimplemented!()
199 /// }
200 /// }
201 /// ```
202 type Context: for<'w, 's> ReadOnlySystemParam<Item<'w, 's>: Send + Sync>;
203
204 /// Computes the [Axis-Aligned Bounding Box](ColliderAabb) of the collider
205 /// with the given position and rotation.
206 ///
207 /// See [`SimpleCollider::aabb`] for collider types with empty [`AnyCollider::Context`]
208 #[cfg_attr(
209 feature = "2d",
210 doc = "\n\nThe rotation is counterclockwise and in radians."
211 )]
212 fn aabb_with_context(
213 &self,
214 position: Vector,
215 rotation: impl Into<Rotation>,
216 context: AabbContext<Self::Context>,
217 ) -> ColliderAabb;
218
219 /// Computes the swept [Axis-Aligned Bounding Box](ColliderAabb) of the collider.
220 /// This corresponds to the space the shape would occupy if it moved from the given
221 /// start position to the given end position.
222 ///
223 /// See [`SimpleCollider::swept_aabb`] for collider types with empty [`AnyCollider::Context`]
224 #[cfg_attr(
225 feature = "2d",
226 doc = "\n\nThe rotation is counterclockwise and in radians."
227 )]
228 fn swept_aabb_with_context(
229 &self,
230 start_position: Vector,
231 start_rotation: impl Into<Rotation>,
232 end_position: Vector,
233 end_rotation: impl Into<Rotation>,
234 context: AabbContext<Self::Context>,
235 ) -> ColliderAabb {
236 self.aabb_with_context(start_position, start_rotation, context.clone())
237 .merged(self.aabb_with_context(end_position, end_rotation, context))
238 }
239
240 /// Computes all [`ContactManifold`]s between two colliders.
241 ///
242 /// Returns an empty vector if the colliders are separated by a distance greater than `prediction_distance`
243 /// or if the given shapes are invalid.
244 ///
245 /// See [`SimpleCollider::contact_manifolds`] for collider types with empty [`AnyCollider::Context`]
246 fn contact_manifolds_with_context(
247 &self,
248 other: &Self,
249 position1: Vector,
250 rotation1: impl Into<Rotation>,
251 position2: Vector,
252 rotation2: impl Into<Rotation>,
253 prediction_distance: Scalar,
254 manifolds: &mut Vec<ContactManifold>,
255 context: ContactManifoldContext<Self::Context>,
256 );
257}
258
259/// A simplified wrapper around [`AnyCollider`] that doesn't require passing in the context for
260/// implementations that don't need context
261pub trait SimpleCollider: AnyCollider<Context = ()> {
262 /// Computes the [Axis-Aligned Bounding Box](ColliderAabb) of the collider
263 /// with the given position and rotation.
264 ///
265 /// See [`AnyCollider::aabb_with_context`] for collider types with non-empty [`AnyCollider::Context`]
266 fn aabb(&self, position: Vector, rotation: impl Into<Rotation>) -> ColliderAabb {
267 self.aabb_with_context(position, rotation, AabbContext::fake())
268 }
269
270 /// Computes the swept [Axis-Aligned Bounding Box](ColliderAabb) of the collider.
271 /// This corresponds to the space the shape would occupy if it moved from the given
272 /// start position to the given end position.
273 ///
274 /// See [`AnyCollider::swept_aabb_with_context`] for collider types with non-empty [`AnyCollider::Context`]
275 fn swept_aabb(
276 &self,
277 start_position: Vector,
278 start_rotation: impl Into<Rotation>,
279 end_position: Vector,
280 end_rotation: impl Into<Rotation>,
281 ) -> ColliderAabb {
282 self.swept_aabb_with_context(
283 start_position,
284 start_rotation,
285 end_position,
286 end_rotation,
287 AabbContext::fake(),
288 )
289 }
290
291 /// Computes all [`ContactManifold`]s between two colliders, writing the results into `manifolds`.
292 ///
293 /// `manifolds` is cleared if the colliders are separated by a distance greater than `prediction_distance`
294 /// or if the given shapes are invalid.
295 ///
296 /// See [`AnyCollider::contact_manifolds_with_context`] for collider types with non-empty [`AnyCollider::Context`]
297 fn contact_manifolds(
298 &self,
299 other: &Self,
300 position1: Vector,
301 rotation1: impl Into<Rotation>,
302 position2: Vector,
303 rotation2: impl Into<Rotation>,
304 prediction_distance: Scalar,
305 manifolds: &mut Vec<ContactManifold>,
306 ) {
307 self.contact_manifolds_with_context(
308 other,
309 position1,
310 rotation1,
311 position2,
312 rotation2,
313 prediction_distance,
314 manifolds,
315 ContactManifoldContext::fake(),
316 )
317 }
318}
319
320impl<C: AnyCollider<Context = ()>> SimpleCollider for C {}
321
322/// A trait for colliders that support scaling.
323pub trait ScalableCollider: AnyCollider {
324 /// Returns the global scaling factor of the collider.
325 fn scale(&self) -> Vector;
326
327 /// Sets the global scaling factor of the collider.
328 ///
329 /// If the scaling factor is not uniform and the resulting scaled shape
330 /// can not be represented exactly, the given `detail` is used for an approximation.
331 fn set_scale(&mut self, scale: Vector, detail: u32);
332
333 /// Scales the collider by the given scaling factor.
334 ///
335 /// If the scaling factor is not uniform and the resulting scaled shape
336 /// can not be represented exactly, the given `detail` is used for an approximation.
337 fn scale_by(&mut self, factor: Vector, detail: u32) {
338 self.set_scale(factor * self.scale(), detail)
339 }
340}
341
342/// A marker component that indicates that a [collider](Collider) is disabled
343/// and should not detect collisions or be included in spatial queries.
344///
345/// This is useful for temporarily disabling a collider without removing it from the world.
346/// To re-enable the collider, simply remove this component.
347///
348/// Note that a disabled collider will still contribute to the mass properties of the rigid body
349/// it is attached to. Set the [`Mass`] of the collider to zero to prevent this.
350///
351/// [`ColliderDisabled`] only applies to the entity it is attached to, not its children.
352///
353/// # Example
354///
355/// ```
356#[cfg_attr(feature = "2d", doc = "# use avian2d::prelude::*;")]
357#[cfg_attr(feature = "3d", doc = "# use avian3d::prelude::*;")]
358/// # use bevy::prelude::*;
359/// #
360/// #[derive(Component)]
361/// pub struct Character;
362///
363/// /// Disables colliders for all rigid body characters, for example during cutscenes.
364/// fn disable_character_colliders(
365/// mut commands: Commands,
366/// query: Query<Entity, (With<RigidBody>, With<Character>)>,
367/// ) {
368/// for entity in &query {
369/// commands.entity(entity).insert(ColliderDisabled);
370/// }
371/// }
372///
373/// /// Enables colliders for all rigid body characters.
374/// fn enable_character_colliders(
375/// mut commands: Commands,
376/// query: Query<Entity, (With<RigidBody>, With<Character>)>,
377/// ) {
378/// for entity in &query {
379/// commands.entity(entity).remove::<ColliderDisabled>();
380/// }
381/// }
382/// ```
383///
384/// # Related Components
385///
386/// - [`RigidBodyDisabled`]: Disables a rigid body.
387/// - [`JointDisabled`]: Disables a joint constraint.
388#[derive(Reflect, Clone, Copy, Component, Debug, Default)]
389#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
390#[cfg_attr(feature = "serialize", reflect(Serialize, Deserialize))]
391#[reflect(Debug, Component, Default)]
392pub struct ColliderDisabled;
393
394/// A component that marks a [`Collider`] as a sensor, also known as a trigger.
395///
396/// Sensor colliders send [collision events](crate::collision#collision-events) and register intersections,
397/// but allow other bodies to pass through them. This is often used to detect when something enters
398/// or leaves an area or is intersecting some shape.
399///
400/// Sensor colliders do *not* contribute to the mass properties of rigid bodies.
401///
402/// # Example
403///
404/// ```
405#[cfg_attr(feature = "2d", doc = "use avian2d::prelude::*;")]
406#[cfg_attr(feature = "3d", doc = "use avian3d::prelude::*;")]
407/// use bevy::prelude::*;
408///
409/// fn setup(mut commands: Commands) {
410/// // Spawn a static body with a sensor collider.
411/// // Other bodies will pass through, but it will still send collision events.
412#[cfg_attr(
413 feature = "2d",
414 doc = " commands.spawn((RigidBody::Static, Collider::circle(0.5), Sensor));"
415)]
416#[cfg_attr(
417 feature = "3d",
418 doc = " commands.spawn((RigidBody::Static, Collider::sphere(0.5), Sensor));"
419)]
420/// }
421/// ```
422#[doc(alias = "Trigger")]
423#[derive(Reflect, Clone, Component, Debug, Default, PartialEq, Eq)]
424#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
425#[cfg_attr(feature = "serialize", reflect(Serialize, Deserialize))]
426#[reflect(Debug, Component, Default, PartialEq)]
427pub struct Sensor;
428
429/// The Axis-Aligned Bounding Box of a [collider](Collider) in world space.
430///
431/// This is updated automatically.
432#[derive(Reflect, Clone, Copy, Component, Debug, PartialEq)]
433#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
434#[cfg_attr(feature = "serialize", reflect(Serialize, Deserialize))]
435#[reflect(Debug, Component, PartialEq)]
436pub struct ColliderAabb {
437 /// The minimum point of the AABB.
438 pub min: Vector,
439 /// The maximum point of thr AABB.
440 pub max: Vector,
441}
442
443impl Default for ColliderAabb {
444 fn default() -> Self {
445 ColliderAabb::INVALID
446 }
447}
448
449impl ColliderAabb {
450 /// An invalid [`ColliderAabb`] that represents an empty AABB.
451 pub const INVALID: Self = Self {
452 min: Vector::INFINITY,
453 max: Vector::NEG_INFINITY,
454 };
455
456 /// Creates a new [`ColliderAabb`] from the given `center` and `half_size`.
457 pub fn new(center: Vector, half_size: Vector) -> Self {
458 Self {
459 min: center - half_size,
460 max: center + half_size,
461 }
462 }
463
464 /// Creates a new [`ColliderAabb`] from its minimum and maximum points.
465 pub fn from_min_max(min: Vector, max: Vector) -> Self {
466 Self { min, max }
467 }
468
469 /// Creates a new [`ColliderAabb`] from a given `SharedShape`.
470 #[cfg(all(
471 feature = "default-collider",
472 any(feature = "parry-f32", feature = "parry-f64")
473 ))]
474 pub fn from_shape(shape: &crate::parry::shape::SharedShape) -> Self {
475 let aabb = shape.compute_local_aabb();
476 Self {
477 min: aabb.mins.into(),
478 max: aabb.maxs.into(),
479 }
480 }
481
482 /// Computes the center of the AABB,
483 #[inline(always)]
484 pub fn center(self) -> Vector {
485 self.min.midpoint(self.max)
486 }
487
488 /// Computes the size of the AABB.
489 #[inline(always)]
490 pub fn size(self) -> Vector {
491 self.max - self.min
492 }
493
494 /// Merges this AABB with another one.
495 #[inline(always)]
496 pub fn merged(self, other: Self) -> Self {
497 ColliderAabb {
498 min: self.min.min(other.min),
499 max: self.max.max(other.max),
500 }
501 }
502
503 /// Increases the size of the bounding volume in each direction by the given amount.
504 #[inline(always)]
505 pub fn grow(&self, amount: Vector) -> Self {
506 let b = Self {
507 min: self.min - amount,
508 max: self.max + amount,
509 };
510 debug_assert!(b.min.cmple(b.max).all());
511 b
512 }
513
514 /// Decreases the size of the bounding volume in each direction by the given amount.
515 #[inline(always)]
516 pub fn shrink(&self, amount: Vector) -> Self {
517 let b = Self {
518 min: self.min + amount,
519 max: self.max - amount,
520 };
521 debug_assert!(b.min.cmple(b.max).all());
522 b
523 }
524
525 /// Checks if `self` intersects with `other`.
526 #[inline(always)]
527 #[cfg(feature = "2d")]
528 pub fn intersects(&self, other: &Self) -> bool {
529 let x_overlaps = self.min.x <= other.max.x && self.max.x >= other.min.x;
530 let y_overlaps = self.min.y <= other.max.y && self.max.y >= other.min.y;
531 x_overlaps && y_overlaps
532 }
533
534 /// Checks if `self` intersects with `other`.
535 #[inline(always)]
536 #[cfg(feature = "3d")]
537 pub fn intersects(&self, other: &Self) -> bool {
538 let x_overlaps = self.min.x <= other.max.x && self.max.x >= other.min.x;
539 let y_overlaps = self.min.y <= other.max.y && self.max.y >= other.min.y;
540 let z_overlaps = self.min.z <= other.max.z && self.max.z >= other.min.z;
541 x_overlaps && y_overlaps && z_overlaps
542 }
543}
544
545/// A component that adds an extra margin or "skin" around [`Collider`] shapes to help maintain
546/// additional separation to other objects. This added thickness can help improve
547/// stability and performance in some cases, especially for thin shapes such as trimeshes.
548///
549/// There are three primary reasons for collision margins:
550///
551/// 1. Collision detection is often more efficient when shapes are not overlapping
552/// further than their collision margins. Deeply overlapping shapes require
553/// more expensive collision algorithms.
554///
555/// 2. Some shapes such as triangles and planes are infinitely thin,
556/// which can cause precision errors. A collision margin adds artificial
557/// thickness to shapes, improving stability.
558///
559/// 3. Overall, collision margins give the physics engine more
560/// room for error when resolving contacts. This can also help
561/// prevent visible artifacts such as objects poking through the ground.
562///
563/// If a rigid body with a [`CollisionMargin`] has colliders as child entities,
564/// and those colliders don't have their own [`CollisionMargin`] components,
565/// the colliders will use the rigid body's [`CollisionMargin`].
566///
567/// # Example
568///
569/// ```
570#[cfg_attr(feature = "2d", doc = "use avian2d::prelude::*;")]
571#[cfg_attr(feature = "3d", doc = "use avian3d::prelude::*;")]
572/// use bevy::prelude::*;
573///
574/// fn setup(mut commands: Commands) {
575#[cfg_attr(
576 feature = "2d",
577 doc = " // Spawn a rigid body with a collider.
578 // A margin of `0.1` is added around the shape.
579 commands.spawn((
580 RigidBody::Dynamic,
581 Collider::capsule(2.0, 0.5),
582 CollisionMargin(0.1),
583 ));"
584)]
585#[cfg_attr(
586 feature = "3d",
587 doc = " let mesh = Mesh::from(Torus::default());
588
589 // Spawn a rigid body with a triangle mesh collider.
590 // A margin of `0.1` is added around the shape.
591 commands.spawn((
592 RigidBody::Dynamic,
593 Collider::trimesh_from_mesh(&mesh).unwrap(),
594 CollisionMargin(0.1),
595 ));"
596)]
597/// }
598/// ```
599#[derive(Reflect, Clone, Copy, Component, Debug, Default, Deref, DerefMut, PartialEq, From)]
600#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
601#[cfg_attr(feature = "serialize", reflect(Serialize, Deserialize))]
602#[reflect(Component)]
603#[doc(alias = "ContactSkin")]
604pub struct CollisionMargin(pub Scalar);
605
606/// A component for reading which entities are colliding with a collider entity.
607/// Must be added manually for desired colliders.
608///
609/// # Example
610///
611/// ```
612#[cfg_attr(feature = "2d", doc = "use avian2d::prelude::*;")]
613#[cfg_attr(feature = "3d", doc = "use avian3d::prelude::*;")]
614/// use bevy::prelude::*;
615///
616/// fn setup(mut commands: Commands) {
617/// commands.spawn((
618/// RigidBody::Dynamic,
619/// Collider::capsule(0.5, 1.5),
620/// // Add the `CollidingEntities` component to read entities colliding with this entity.
621/// CollidingEntities::default(),
622/// ));
623/// }
624///
625/// fn my_system(query: Query<(Entity, &CollidingEntities)>) {
626/// for (entity, colliding_entities) in &query {
627/// println!(
628/// "{} is colliding with the following entities: {:?}",
629/// entity,
630/// colliding_entities,
631/// );
632/// }
633/// }
634/// ```
635#[derive(Reflect, Clone, Component, Debug, Default, Deref, DerefMut, PartialEq, Eq)]
636#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
637#[cfg_attr(feature = "serialize", reflect(Serialize, Deserialize))]
638#[reflect(Debug, Component, Default, PartialEq)]
639pub struct CollidingEntities(pub EntityHashSet);
640
641impl MapEntities for CollidingEntities {
642 fn map_entities<M: EntityMapper>(&mut self, entity_mapper: &mut M) {
643 self.0 = self
644 .0
645 .clone()
646 .into_iter()
647 .map(|e| entity_mapper.get_mapped(e))
648 .collect()
649 }
650}