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