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