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}