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}