Skip to main content

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 for operations involving an [`AnyCollider`].
57#[derive(Deref)]
58pub struct ColliderContext<'a, 'w, 's, T: ReadOnlySystemParam> {
59    /// The collider entity involved in the operation.
60    pub collider: Entity,
61    #[deref]
62    item: &'a SystemParamItem<'w, 's, T>,
63}
64
65impl<T: ReadOnlySystemParam> Clone for ColliderContext<'_, '_, '_, T> {
66    fn clone(&self) -> Self {
67        Self {
68            collider: self.collider,
69            item: self.item,
70        }
71    }
72}
73
74impl<'a, 'w, 's, T: ReadOnlySystemParam> ColliderContext<'a, 'w, 's, T> {
75    /// Constructs a [`ColliderContext`].
76    pub fn new(collider: Entity, item: &'a <T as SystemParam>::Item<'w, 's>) -> Self {
77        Self { collider, item }
78    }
79}
80
81impl ColliderContext<'_, '_, '_, ()> {
82    /// No context is needed for this collider.
83    const NO_CONTEXT: Self = Self {
84        collider: Entity::PLACEHOLDER,
85        item: &(),
86    };
87}
88
89/// Context necessary for operations involving a pair of [`AnyCollider`]s.
90#[derive(Deref)]
91pub struct ColliderPairContext<'a, 'w, 's, T: ReadOnlySystemParam> {
92    /// The first collider entity involved in the operation.
93    pub collider1: Entity,
94    /// The second collider entity involved in the operation.
95    pub collider2: Entity,
96    #[deref]
97    item: &'a SystemParamItem<'w, 's, T>,
98}
99
100impl<'a, 'w, 's, T: ReadOnlySystemParam> ColliderPairContext<'a, 'w, 's, T> {
101    /// Constructs a [`ColliderPairContext`].
102    pub fn new(
103        collider1: Entity,
104        collider2: Entity,
105        item: &'a <T as SystemParam>::Item<'w, 's>,
106    ) -> Self {
107        Self {
108            collider1,
109            collider2,
110            item,
111        }
112    }
113}
114
115impl ColliderPairContext<'_, '_, '_, ()> {
116    /// No context is needed for this collider pair.
117    const NO_CONTEXT: Self = Self {
118        collider1: Entity::PLACEHOLDER,
119        collider2: Entity::PLACEHOLDER,
120        item: &(),
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(feature = "2d", doc = "# use avian2d::{prelude::*, math::RVector};")]
138    #[cfg_attr(feature = "3d", doc = "# use avian3d::{prelude::*, math::RVector};")]
139    /// # use bevy::prelude::*;
140    /// # use bevy::ecs::system::{SystemParam, lifetimeless::{SRes, SQuery}};
141    /// #
142    /// #[derive(Component)]
143    /// pub struct VoxelCollider;
144    ///
145    /// #[derive(Component)]
146    /// pub struct VoxelData {
147    ///     // collider voxel data...
148    /// }
149    ///
150    /// # impl ComputeMassProperties2d for VoxelCollider {
151    /// #     fn mass(&self, density: f32) -> f32 {0.}
152    /// #     fn unit_angular_inertia(&self) -> f32 { 0.}
153    /// #     fn center_of_mass(&self) -> Vec2 { Vec2::ZERO }
154    /// # }
155    /// #
156    /// # impl ComputeMassProperties3d for VoxelCollider {
157    /// #     fn mass(&self, density: f32) -> f32 {0.}
158    /// #     fn unit_principal_angular_inertia(&self) -> Vec3 { Vec3::ZERO }
159    /// #     fn center_of_mass(&self) -> Vec3 { Vec3::ZERO }
160    /// # }
161    /// #
162    /// impl AnyCollider for VoxelCollider {
163    ///     type Context = (
164    ///         // you can query extra components here
165    ///         SQuery<&'static VoxelData>,
166    ///         // or put any other read-only system param here
167    ///         SRes<Time>,
168    ///     );
169    ///
170    /// #   fn aabb_with_context(
171    /// #       &self,
172    /// #       _: RVector,
173    #[cfg_attr(feature = "2d", doc = "#       _: impl Into<Rot2>,")]
174    #[cfg_attr(feature = "3d", doc = "#       _: impl Into<Quat>,")]
175    /// #       _: f32,
176    /// #       _: ColliderContext<Self::Context>,
177    /// #   ) -> ColliderAabb { unimplemented!() }
178    /// #
179    ///     fn contact_manifolds_with_context(
180    ///         &self,
181    ///         other: &Self,
182    ///         position1: RVector,
183    #[cfg_attr(feature = "2d", doc = "        rotation1: impl Into<Rot2>,")]
184    #[cfg_attr(feature = "3d", doc = "        rotation1: impl Into<Quat>,")]
185    ///         position2: RVector,
186    #[cfg_attr(feature = "2d", doc = "        rotation2: impl Into<Rot2>,")]
187    #[cfg_attr(feature = "3d", doc = "        rotation2: impl Into<Quat>,")]
188    ///         prediction_distance: f32,
189    ///         manifolds: &mut Vec<ContactManifold>,
190    ///         context: ColliderPairContext<Self::Context>,
191    ///     ) {
192    ///         let [voxels1, voxels2] = context.0.get_many([context.collider1, context.collider2])
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, grown by the given margin.
204    ///
205    /// See [`SimpleCollider::aabb`] for collider types with an 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: RVector,
213        rotation: impl Into<Rot>,
214        margin: f32,
215        context: ColliderContext<Self::Context>,
216    ) -> ColliderAabb;
217
218    /// Computes the swept [Axis-Aligned Bounding Box](ColliderAabb) of the collider,
219    /// grown by the given margin. This corresponds to the space the shape would occupy
220    /// if it moved from the given start position to the given end position.
221    ///
222    /// See [`SimpleCollider::swept_aabb`] for collider types with an empty [`AnyCollider::Context`].
223    #[cfg_attr(
224        feature = "2d",
225        doc = "\n\nThe rotation is counterclockwise and in radians."
226    )]
227    fn swept_aabb_with_context(
228        &self,
229        start_position: RVector,
230        start_rotation: impl Into<Rot>,
231        end_position: RVector,
232        end_rotation: impl Into<Rot>,
233        margin: f32,
234        context: ColliderContext<Self::Context>,
235    ) -> ColliderAabb {
236        self.aabb_with_context(start_position, start_rotation, margin, context.clone())
237            .merged(self.aabb_with_context(end_position, end_rotation, margin, 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 an empty [`AnyCollider::Context`].
246    fn contact_manifolds_with_context(
247        &self,
248        other: &Self,
249        position1: RVector,
250        rotation1: impl Into<Rot>,
251        position2: RVector,
252        rotation2: impl Into<Rot>,
253        prediction_distance: f32,
254        manifolds: &mut Vec<ContactManifold>,
255        context: ColliderPairContext<Self::Context>,
256    );
257
258    /// Returns a conservative minimum thickness used by [Continuous Collision Detection (CCD)][CCD]
259    /// to determine when the collider might tunnel through other geometry.
260    ///
261    /// Typically corresponds to the minimum distance from the centroid
262    /// of any given shape to its surface.
263    ///
264    /// [CCD]: crate::dynamics::ccd
265    fn ccd_thickness_with_context(&self, context: ColliderContext<Self::Context>) -> f32 {
266        let aabb = self.aabb_with_context(RVector::ZERO, Rot::IDENTITY, 0.0, context);
267        aabb.size().min_element() * 0.5
268    }
269
270    /// Returns the maximum distance from the collider to the given point.
271    fn max_distance_to_point_with_context(
272        &self,
273        point: RVector,
274        context: ColliderContext<Self::Context>,
275    ) -> f32 {
276        let aabb = self.aabb_with_context(RVector::ZERO, Rot::IDENTITY, 0.0, context);
277        point.distance(aabb.center()).f32() + aabb.size().length() * 0.5
278    }
279
280    /// Returns the radius of the bounding sphere of the collider.
281    ///
282    /// This is used to compute a size-relative [`ColliderAabbMargin`] for the collider.
283    fn bounding_radius_with_context(&self, context: ColliderContext<Self::Context>) -> f32 {
284        // We don't have a bounding sphere method directly available here,
285        // so for now we settle for this approximation for the default implementation.
286        let aabb = self.aabb_with_context(RVector::ZERO, Rot::IDENTITY, 0.0, context.clone());
287        aabb.size().length() * 0.5
288    }
289}
290
291/// A simplified wrapper around [`AnyCollider`] that doesn't require passing in the context for
292/// implementations that don't need context
293pub trait SimpleCollider: AnyCollider<Context = ()> {
294    /// Computes the [Axis-Aligned Bounding Box](ColliderAabb) of the collider
295    /// with the given position and rotation, grown by the given margin.
296    ///
297    /// See [`AnyCollider::aabb_with_context`] for collider types with a non-empty [`AnyCollider::Context`].
298    fn aabb(&self, position: RVector, rotation: impl Into<Rot>, margin: f32) -> ColliderAabb {
299        self.aabb_with_context(position, rotation, margin, ColliderContext::NO_CONTEXT)
300    }
301
302    /// Computes the swept [Axis-Aligned Bounding Box](ColliderAabb) of the collider,
303    /// grown by the given margin. This corresponds to the space the shape would occupy
304    /// if it moved from the given start position to the given end position.
305    ///
306    /// See [`AnyCollider::swept_aabb_with_context`] for collider types with a non-empty [`AnyCollider::Context`].
307    fn swept_aabb(
308        &self,
309        start_position: RVector,
310        start_rotation: impl Into<Rot>,
311        end_position: RVector,
312        end_rotation: impl Into<Rot>,
313        margin: f32,
314    ) -> ColliderAabb {
315        self.swept_aabb_with_context(
316            start_position,
317            start_rotation,
318            end_position,
319            end_rotation,
320            margin,
321            ColliderContext::NO_CONTEXT,
322        )
323    }
324
325    /// Computes all [`ContactManifold`]s between two colliders, writing the results into `manifolds`.
326    ///
327    /// `manifolds` is cleared if the colliders are separated by a distance greater than `prediction_distance`
328    /// or if the given shapes are invalid.
329    ///
330    /// See [`AnyCollider::contact_manifolds_with_context`] for collider types with a non-empty [`AnyCollider::Context`].
331    fn contact_manifolds(
332        &self,
333        other: &Self,
334        position1: RVector,
335        rotation1: impl Into<Rot>,
336        position2: RVector,
337        rotation2: impl Into<Rot>,
338        prediction_distance: f32,
339        manifolds: &mut Vec<ContactManifold>,
340    ) {
341        self.contact_manifolds_with_context(
342            other,
343            position1,
344            rotation1,
345            position2,
346            rotation2,
347            prediction_distance,
348            manifolds,
349            ColliderPairContext::NO_CONTEXT,
350        )
351    }
352
353    /// Returns a conservative minimum thickness used by [Continuous Collision Detection (CCD)][CCD]
354    /// to determine when the collider might tunnel through other geometry.
355    ///
356    /// Typically corresponds to the minimum distance from the centroid
357    /// of any given shape to its surface.
358    ///
359    /// [CCD]: crate::dynamics::ccd
360    fn ccd_thickness(&self) -> f32 {
361        self.ccd_thickness_with_context(ColliderContext::NO_CONTEXT)
362    }
363
364    /// Returns the maximum distance from the collider to the given point.
365    fn max_distance_to_point(&self, point: RVector) -> f32 {
366        self.max_distance_to_point_with_context(point, ColliderContext::NO_CONTEXT)
367    }
368
369    /// Returns the radius of the bounding sphere of the collider.
370    ///
371    /// This is used to compute a size-relative [`ColliderAabbMargin`] for the collider.
372    fn bounding_radius(&self) -> f32 {
373        self.bounding_radius_with_context(ColliderContext::NO_CONTEXT)
374    }
375}
376
377impl<C: AnyCollider<Context = ()>> SimpleCollider for C {}
378
379/// A trait for colliders that support scaling.
380pub trait ScalableCollider: AnyCollider {
381    /// Returns the global scaling factor of the collider.
382    fn scale(&self) -> Vector;
383
384    /// Sets the global scaling factor of the collider.
385    ///
386    /// If the scaling factor is not uniform and the resulting scaled shape
387    /// can not be represented exactly, the given `detail` is used for an approximation.
388    fn set_scale(&mut self, scale: Vector, detail: u32);
389
390    /// Scales the collider by the given scaling factor.
391    ///
392    /// If the scaling factor is not uniform and the resulting scaled shape
393    /// can not be represented exactly, the given `detail` is used for an approximation.
394    fn scale_by(&mut self, factor: Vector, detail: u32) {
395        self.set_scale(factor * self.scale(), detail)
396    }
397}
398
399/// A marker component that indicates that a [collider](Collider) is disabled
400/// and should not detect collisions or be included in spatial queries.
401///
402/// This is useful for temporarily disabling a collider without removing it from the world.
403/// To re-enable the collider, simply remove this component.
404///
405/// Note that a disabled collider will still contribute to the mass properties of the rigid body
406/// it is attached to. Set the [`Mass`] of the collider to zero to prevent this.
407///
408/// [`ColliderDisabled`] only applies to the entity it is attached to, not its children.
409///
410/// # Example
411///
412/// ```
413#[cfg_attr(feature = "2d", doc = "# use avian2d::prelude::*;")]
414#[cfg_attr(feature = "3d", doc = "# use avian3d::prelude::*;")]
415/// # use bevy::prelude::*;
416/// #
417/// #[derive(Component)]
418/// pub struct Character;
419///
420/// /// Disables colliders for all rigid body characters, for example during cutscenes.
421/// fn disable_character_colliders(
422///     mut commands: Commands,
423///     query: Query<Entity, (With<RigidBody>, With<Character>)>,
424/// ) {
425///     for entity in &query {
426///         commands.entity(entity).insert(ColliderDisabled);
427///     }
428/// }
429///
430/// /// Enables colliders for all rigid body characters.
431/// fn enable_character_colliders(
432///     mut commands: Commands,
433///     query: Query<Entity, (With<RigidBody>, With<Character>)>,
434/// ) {
435///     for entity in &query {
436///         commands.entity(entity).remove::<ColliderDisabled>();
437///     }
438/// }
439/// ```
440///
441/// # Related Components
442///
443/// - [`RigidBodyDisabled`]: Disables a rigid body.
444/// - [`JointDisabled`]: Disables a joint constraint.
445#[derive(Reflect, Clone, Copy, Component, Debug, Default)]
446#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
447#[cfg_attr(feature = "serialize", reflect(Serialize, Deserialize))]
448#[reflect(Debug, Component, Default)]
449pub struct ColliderDisabled;
450
451/// A component that marks a [`Collider`] as a sensor, also known as a trigger.
452///
453/// Sensor colliders send [collision events](crate::collision#collision-events) and register intersections,
454/// but allow other bodies to pass through them. This is often used to detect when something enters
455/// or leaves an area or is intersecting some shape.
456///
457/// Sensor colliders do *not* contribute to the mass properties of rigid bodies.
458///
459/// # Example
460///
461/// ```
462#[cfg_attr(feature = "2d", doc = "use avian2d::prelude::*;")]
463#[cfg_attr(feature = "3d", doc = "use avian3d::prelude::*;")]
464/// use bevy::prelude::*;
465///
466/// fn setup(mut commands: Commands) {
467///     // Spawn a static body with a sensor collider.
468///     // Other bodies will pass through, but it will still send collision events.
469#[cfg_attr(
470    feature = "2d",
471    doc = "    commands.spawn((RigidBody::Static, Collider::circle(0.5), Sensor));"
472)]
473#[cfg_attr(
474    feature = "3d",
475    doc = "    commands.spawn((RigidBody::Static, Collider::sphere(0.5), Sensor));"
476)]
477/// }
478/// ```
479#[doc(alias = "Trigger")]
480#[derive(Reflect, Clone, Component, Debug, Default, PartialEq, Eq)]
481#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
482#[cfg_attr(feature = "serialize", reflect(Serialize, Deserialize))]
483#[reflect(Debug, Component, Default, PartialEq)]
484pub struct Sensor;
485
486/// The Axis-Aligned Bounding Box of a [collider](Collider) in world space.
487///
488/// This is updated automatically.
489///
490/// # Large Worlds
491///
492/// When the `f64` feature is enabled, the AABB still uses
493/// single-precision coordinates for BVH performance reasons,
494/// but rounds outward to ensure that it encompasses the collider.
495/// When the shape is far from the origin, its bounds may become more
496/// conservative and inflated due to the limited precision of `f32`.
497///
498/// At `1e7` units from the origin, the floating-point quantization
499/// is about one unit, while at `1e8` units from the origin, it is
500/// about sixteen units. The simulation should still behave correctly,
501/// but the effectiveness of the broad phase and its acceleration structures
502/// may be reduced, as they will report more false positives. It is recommended
503/// to remain within `1e7` to `1e8` units from the origin to not degrade
504/// broad phase performance too much.
505#[derive(Reflect, Clone, Copy, Component, Debug, PartialEq)]
506#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
507#[cfg_attr(feature = "serialize", reflect(Serialize, Deserialize))]
508#[reflect(Debug, Component, PartialEq)]
509pub struct ColliderAabb {
510    /// The minimum point of the AABB.
511    pub min: Vector,
512    /// The maximum point of the AABB.
513    pub max: Vector,
514}
515
516impl Default for ColliderAabb {
517    fn default() -> Self {
518        ColliderAabb::INVALID
519    }
520}
521
522impl ColliderAabb {
523    /// An invalid [`ColliderAabb`] that represents an empty AABB.
524    pub const INVALID: Self = Self {
525        min: Vector::INFINITY,
526        max: Vector::NEG_INFINITY,
527    };
528
529    /// Creates a new [`ColliderAabb`] from the given `center` and `half_size`.
530    pub fn new(center: RVector, half_size: Vector) -> Self {
531        Self {
532            min: next_down_vector(center - half_size.real()),
533            max: next_up_vector(center + half_size.real()),
534        }
535    }
536
537    /// Creates a new [`ColliderAabb`] from its minimum and maximum points.
538    pub fn from_min_max(min: RVector, max: RVector) -> Self {
539        Self {
540            min: next_down_vector(min),
541            max: next_up_vector(max),
542        }
543    }
544
545    /// Creates a new [`ColliderAabb`] from a given `SharedShape`.
546    #[cfg(all(
547        feature = "default-collider",
548        any(feature = "parry-f32", feature = "parry-f64")
549    ))]
550    pub fn from_shape(shape: &crate::parry::shape::SharedShape) -> Self {
551        let aabb = shape.compute_local_aabb();
552        Self {
553            min: next_down_vector(aabb.mins),
554            max: next_up_vector(aabb.maxs),
555        }
556    }
557
558    /// Computes the center of the AABB,
559    #[inline(always)]
560    pub fn center(self) -> RVector {
561        self.min.real().midpoint(self.max.real())
562    }
563
564    /// Computes the size of the AABB.
565    #[inline(always)]
566    pub fn size(self) -> Vector {
567        self.max - self.min
568    }
569
570    /// Computes the half-size of the AABB.
571    #[inline(always)]
572    pub fn half_size(self) -> Vector {
573        self.size() * 0.5
574    }
575
576    /// Merges this AABB with another one.
577    #[inline(always)]
578    pub fn merged(self, other: Self) -> Self {
579        ColliderAabb {
580            min: self.min.min(other.min),
581            max: self.max.max(other.max),
582        }
583    }
584
585    /// Increases the size of the bounding volume in each direction by the given amount.
586    #[inline(always)]
587    pub fn grow(&self, amount: Vector) -> Self {
588        let b = Self {
589            min: self.min - amount,
590            max: self.max + amount,
591        };
592        debug_assert!(b.min.cmple(b.max).all());
593        b
594    }
595
596    /// Decreases the size of the bounding volume in each direction by the given amount.
597    #[inline(always)]
598    pub fn shrink(&self, amount: Vector) -> Self {
599        let b = Self {
600            min: self.min + amount,
601            max: self.max - amount,
602        };
603        debug_assert!(b.min.cmple(b.max).all());
604        b
605    }
606
607    /// Checks if `self` intersects with `other`.
608    #[inline(always)]
609    #[cfg(feature = "2d")]
610    pub fn intersects(&self, other: &Self) -> bool {
611        let x_overlaps = self.min.x <= other.max.x && self.max.x >= other.min.x;
612        let y_overlaps = self.min.y <= other.max.y && self.max.y >= other.min.y;
613        x_overlaps && y_overlaps
614    }
615
616    /// Checks if `self` intersects with `other`.
617    #[inline(always)]
618    #[cfg(feature = "3d")]
619    pub fn intersects(&self, other: &Self) -> bool {
620        let x_overlaps = self.min.x <= other.max.x && self.max.x >= other.min.x;
621        let y_overlaps = self.min.y <= other.max.y && self.max.y >= other.min.y;
622        let z_overlaps = self.min.z <= other.max.z && self.max.z >= other.min.z;
623        x_overlaps && y_overlaps && z_overlaps
624    }
625
626    /// Checks if `self` contains `other`.
627    #[inline(always)]
628    pub fn contains(&self, other: &Self) -> bool {
629        self.min.cmple(other.min).all() && self.max.cmpge(other.max).all()
630    }
631}
632
633impl From<ColliderAabb> for obvhs::aabb::Aabb {
634    fn from(value: ColliderAabb) -> Self {
635        Self {
636            #[cfg(feature = "2d")]
637            min: value.min.extend(-0.5).to_array().into(),
638            #[cfg(feature = "2d")]
639            max: value.max.extend(0.5).to_array().into(),
640            #[cfg(feature = "3d")]
641            min: value.min.to_array().into(),
642            #[cfg(feature = "3d")]
643            max: value.max.to_array().into(),
644        }
645    }
646}
647
648/// An Axis-Aligned Bounding Box that contains the [`ColliderAabb`] with an additional margin.
649///
650/// This is used to avoid updating the [`ColliderTree`] every time a collider moves only a small amount.
651///
652/// The enlarged AABB is updated automatically whenever the [`ColliderAabb`]
653/// moves beyond the bounds of the current enlarged AABB.
654///
655/// [`ColliderTree`]: crate::collider_tree::ColliderTree
656#[derive(Reflect, Clone, Copy, Component, Debug, Default, Deref, PartialEq)]
657#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
658#[cfg_attr(feature = "serialize", reflect(Serialize, Deserialize))]
659#[reflect(Debug, Component, PartialEq)]
660pub struct EnlargedAabb(ColliderAabb);
661
662impl EnlargedAabb {
663    /// Creates a new [`EnlargedAabb`] from the given [`ColliderAabb`].
664    pub fn new(aabb: ColliderAabb) -> Self {
665        Self(aabb)
666    }
667
668    /// Updates the enlarged AABB with the given [`ColliderAabb`] and margin.
669    ///
670    /// If the AABB is already contained within the enlarged AABB, nothing happens.
671    ///
672    /// Returns `true` if the AABB was updated.
673    pub fn update(&mut self, aabb: &ColliderAabb, margin: f32) -> bool {
674        if self.contains(aabb) {
675            return false;
676        }
677
678        let margin = Vector::splat(margin);
679        self.0.min = aabb.min - margin;
680        self.0.max = aabb.max + margin;
681
682        true
683    }
684
685    /// Gets the [`ColliderAabb`] of the enlarged AABB.
686    pub fn get(&self) -> ColliderAabb {
687        self.0
688    }
689}
690
691/// The margin used to enlarge the [`ColliderAabb`] of a collider into its [`EnlargedAabb`].
692///
693/// Enlarging the AABB allows the collider to move by a small amount without triggering
694/// an update of the [`ColliderTree`], which improves performance.
695///
696/// The margin is computed automatically from the size of the collider, scaled relative to the
697/// [`PhysicsLengthUnit`]. Larger shapes get a larger margin (up to [`ColliderAabbMargin::MAX`]),
698/// while small shapes get a margin proportional to their size to avoid wastefully fat AABBs.
699///
700/// [`ColliderTree`]: crate::collider_tree::ColliderTree
701/// [`PhysicsLengthUnit`]: crate::dynamics::solver::PhysicsLengthUnit
702#[derive(Reflect, Clone, Copy, Component, Debug, Default, Deref, PartialEq)]
703#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
704#[cfg_attr(feature = "serialize", reflect(Serialize, Deserialize))]
705#[reflect(Debug, Component, Default, PartialEq)]
706pub struct ColliderAabbMargin(pub f32);
707
708impl ColliderAabbMargin {
709    /// The maximum AABB margin before being scaled by the [`PhysicsLengthUnit`].
710    ///
711    /// This is used to fatten AABBs in the broad phase acceleration structure. This allows proxies
712    /// to move by a small amount without triggering a tree adjustment.
713    ///
714    /// [`PhysicsLengthUnit`]: crate::dynamics::solver::PhysicsLengthUnit
715    pub const MAX: f32 = 0.05;
716
717    /// For small shapes, the margin is limited to this fraction of the shape's bounding radius.
718    pub const FRACTION: f32 = 0.125;
719
720    /// Computes the AABB margin for a collider with the given `bounding_radius` and [`PhysicsLengthUnit`].
721    ///
722    /// The margin is clamped to at most [`ColliderAabbMargin::MAX`] scaled by the length unit,
723    /// and at most [`ColliderAabbMargin::FRACTION`] of the bounding radius for small shapes.
724    ///
725    /// [`PhysicsLengthUnit`]: crate::dynamics::solver::PhysicsLengthUnit
726    #[inline]
727    pub fn from_bounding_radius(bounding_radius: f32, length_unit: f32) -> Self {
728        Self((length_unit * Self::MAX).min(Self::FRACTION * bounding_radius))
729    }
730}
731
732/// A component that adds an extra margin or "skin" around [`Collider`] shapes to help maintain
733/// additional separation to other objects. This added thickness can help improve
734/// stability and performance in some cases, especially for thin shapes such as trimeshes.
735///
736/// There are three primary reasons for collision margins:
737///
738/// 1. Collision detection is often more efficient when shapes are not overlapping
739/// further than their collision margins. Deeply overlapping shapes require
740/// more expensive collision algorithms.
741///
742/// 2. Some shapes such as triangles and planes are infinitely thin,
743/// which can cause precision errors. A collision margin adds artificial
744/// thickness to shapes, improving stability.
745///
746/// 3. Overall, collision margins give the physics engine more
747/// room for error when resolving contacts. This can also help
748/// prevent visible artifacts such as objects poking through the ground.
749///
750/// If a rigid body with a [`CollisionMargin`] has colliders as child entities,
751/// and those colliders don't have their own [`CollisionMargin`] components,
752/// the colliders will use the rigid body's [`CollisionMargin`].
753///
754/// # Example
755///
756/// ```
757#[cfg_attr(feature = "2d", doc = "use avian2d::prelude::*;")]
758#[cfg_attr(feature = "3d", doc = "use avian3d::prelude::*;")]
759/// use bevy::prelude::*;
760///
761/// fn setup(mut commands: Commands) {
762#[cfg_attr(
763    feature = "2d",
764    doc = "    // Spawn a rigid body with a collider.
765    // A margin of `0.1` is added around the shape.
766    commands.spawn((
767        RigidBody::Dynamic,
768        Collider::capsule(2.0, 0.5),
769        CollisionMargin(0.1),
770    ));"
771)]
772#[cfg_attr(
773    feature = "3d",
774    doc = "    let mesh = Mesh::from(Torus::default());
775
776    // Spawn a rigid body with a triangle mesh collider.
777    // A margin of `0.1` is added around the shape.
778    commands.spawn((
779        RigidBody::Dynamic,
780        Collider::trimesh_from_mesh(&mesh).unwrap(),
781        CollisionMargin(0.1),
782    ));"
783)]
784/// }
785/// ```
786#[derive(Reflect, Clone, Copy, Component, Debug, Default, Deref, DerefMut, PartialEq, From)]
787#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
788#[cfg_attr(feature = "serialize", reflect(Serialize, Deserialize))]
789#[reflect(Component)]
790#[doc(alias = "ContactSkin")]
791pub struct CollisionMargin(pub f32);
792
793/// A component for reading which entities are colliding with a collider entity.
794/// Must be added manually for desired colliders.
795///
796/// # Example
797///
798/// ```
799#[cfg_attr(feature = "2d", doc = "use avian2d::prelude::*;")]
800#[cfg_attr(feature = "3d", doc = "use avian3d::prelude::*;")]
801/// use bevy::prelude::*;
802///
803/// fn setup(mut commands: Commands) {
804///     commands.spawn((
805///         RigidBody::Dynamic,
806///         Collider::capsule(0.5, 1.5),
807///         // Add the `CollidingEntities` component to read entities colliding with this entity.
808///         CollidingEntities::default(),
809///     ));
810/// }
811///
812/// fn my_system(query: Query<(Entity, &CollidingEntities)>) {
813///     for (entity, colliding_entities) in &query {
814///         println!(
815///             "{} is colliding with the following entities: {:?}",
816///             entity,
817///             colliding_entities,
818///         );
819///     }
820/// }
821/// ```
822#[derive(Reflect, Clone, Component, Debug, Default, Deref, DerefMut, PartialEq, Eq)]
823#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
824#[cfg_attr(feature = "serialize", reflect(Serialize, Deserialize))]
825#[reflect(Debug, Component, Default, PartialEq)]
826pub struct CollidingEntities(pub EntityHashSet);
827
828impl MapEntities for CollidingEntities {
829    fn map_entities<M: EntityMapper>(&mut self, entity_mapper: &mut M) {
830        self.0 = self
831            .0
832            .clone()
833            .into_iter()
834            .map(|e| entity_mapper.get_mapped(e))
835            .collect()
836    }
837}