Skip to main content

bevy_rapier3d/geometry/
collider.rs

1use std::fmt;
2
3#[cfg(all(feature = "dim3", feature = "async-collider"))]
4use {
5    crate::geometry::{FillMode, MeshConverter, TriMeshFlags, VHACDParameters},
6    crate::math::Real,
7    bevy::platform::collections::HashMap,
8};
9
10use bevy::prelude::*;
11
12use bevy::platform::collections::HashSet;
13use rapier::geometry::Shape;
14use rapier::prelude::{
15    ColliderHandle, InteractionGroups, InteractionTestMode as RapierInteractionTestMode,
16    SharedShape,
17};
18
19use crate::dynamics::{CoefficientCombineRule, MassProperties};
20use crate::math::Vect;
21
22#[cfg(doc)]
23use rapier::{dynamics::RigidBody, geometry::ContactForceEvent};
24
25/// The Rapier handle of a collider that was inserted to the physics scene.
26#[derive(Copy, Clone, Debug, Component)]
27pub struct RapierColliderHandle(pub ColliderHandle);
28
29/// A component which will be replaced by the specified collider type after the referenced mesh become available.
30#[cfg(all(feature = "dim3", feature = "async-collider"))]
31#[derive(Component, Debug, Clone, Default)]
32pub struct AsyncCollider(pub ComputedColliderShape);
33
34/// A component which will be replaced the specified collider types on children with meshes after the referenced scene become available.
35#[cfg(all(feature = "dim3", feature = "async-collider"))]
36#[derive(Component, Debug, Clone)]
37pub struct AsyncSceneCollider {
38    /// Collider type for each scene mesh not included in [`Self::named_shapes`]. If [`None`], then all
39    /// shapes will be skipped for processing except [`Self::named_shapes`].
40    pub shape: Option<ComputedColliderShape>,
41    /// Shape types for meshes by name. If shape is [`None`], then it will be skipped for
42    /// processing.
43    pub named_shapes: HashMap<String, Option<ComputedColliderShape>>,
44}
45
46#[cfg(all(feature = "dim3", feature = "async-collider"))]
47impl Default for AsyncSceneCollider {
48    fn default() -> Self {
49        Self {
50            shape: Some(Default::default()),
51            named_shapes: Default::default(),
52        }
53    }
54}
55
56/// Shape type based on a Bevy mesh asset.
57#[cfg(all(feature = "dim3", feature = "async-collider"))]
58#[derive(Debug, Clone)]
59pub enum ComputedColliderShape {
60    /// Triangle-mesh.
61    TriMesh(TriMeshFlags),
62    /// Convex hull.
63    ConvexHull,
64    /// Convex decomposition.
65    ConvexDecomposition(VHACDParameters),
66    /// Voxelization of the mesh (see [`Collider::voxelized_mesh`]).
67    Voxels {
68        /// The size of each voxel along every axis.
69        voxel_size: Real,
70        /// Controls whether only the voxels intersecting the mesh boundary are kept, or if its
71        /// interior is filled too.
72        fill_mode: FillMode,
73    },
74    /// Shape obtained by converting the mesh with the given [`MeshConverter`] (see
75    /// [`Collider::converted_trimesh`]).
76    Converted(MeshConverter),
77}
78
79#[cfg(all(feature = "dim3", feature = "async-collider"))]
80impl Default for ComputedColliderShape {
81    fn default() -> Self {
82        Self::TriMesh(TriMeshFlags::MERGE_DUPLICATE_VERTICES)
83    }
84}
85
86/// A geometric entity that can be attached to a [`RigidBody`] so it can be affected by contacts
87/// and intersection queries.
88///
89/// Related components:
90/// - [`ColliderMassProperties`]
91/// - [`ReadColliderMassProperties`]
92/// - [`Friction`]
93/// - [`Restitution`]
94/// - [`Sensor`]
95/// - [`CollisionGroups`]
96/// - [`SolverGroups`]
97/// - [`ActiveCollisionTypes`]
98/// - [`ActiveEvents`]
99/// - [`ContactForceEventThreshold`]
100/// - [`CollidingEntities`]
101/// - [`ColliderScale`]
102/// - [`ColliderDisabled`]
103#[derive(Component, Clone)] // TODO: Reflect
104#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
105#[require(ReadColliderMassProperties)]
106pub struct Collider {
107    /// The raw shape from Rapier.
108    pub raw: SharedShape,
109    pub(crate) unscaled: SharedShape,
110    pub(crate) scale: Vect,
111}
112
113impl From<SharedShape> for Collider {
114    fn from(shared_shape: SharedShape) -> Collider {
115        Collider {
116            raw: shared_shape.clone(),
117            unscaled: shared_shape,
118            scale: Vect::ONE,
119        }
120    }
121}
122
123impl<'a> From<&'a Collider> for &'a dyn Shape {
124    fn from(collider: &'a Collider) -> &'a dyn Shape {
125        &*collider.raw
126    }
127}
128
129/// A shape accepted by the scene queries (e.g. [`RapierContext::cast_shape`]) and by
130/// [`RapierContextMut::move_shape`]: a [`Collider`] (its scaled shape), a Rapier shape trait object
131/// (`&dyn Shape`, e.g. `&*shared_shape`), or any concrete Rapier shape (e.g. `Ball`).
132///
133/// [`RapierContext::cast_shape`]: crate::plugin::context::systemparams::RapierContext::cast_shape
134/// [`RapierContextMut::move_shape`]: crate::plugin::context::systemparams::RapierContextMut::move_shape
135pub trait AsShape {
136    /// The shape used by the query.
137    fn as_shape(&self) -> &dyn Shape;
138}
139
140impl AsShape for Collider {
141    fn as_shape(&self) -> &dyn Shape {
142        &*self.raw
143    }
144}
145
146impl AsShape for dyn Shape {
147    fn as_shape(&self) -> &dyn Shape {
148        self
149    }
150}
151
152impl<S: Shape> AsShape for S {
153    fn as_shape(&self) -> &dyn Shape {
154        self
155    }
156}
157
158impl fmt::Debug for Collider {
159    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
160        self.as_typed_shape().fmt(f)
161    }
162}
163
164/// Overwrites the default application of [`GlobalTransform`] scale to a [`Collider`]'s shapes.
165#[derive(Copy, Clone, Debug, PartialEq, Component, Reflect)]
166pub enum ColliderScale {
167    /// This scale will be multiplied with the scale in the [`GlobalTransform`] component
168    /// before being applied to the collider.
169    Relative(Vect),
170    /// This scale will replace the one specified in the [`GlobalTransform`] component.
171    Absolute(Vect),
172}
173
174/// Indicates whether or not the [`Collider`] is a sensor.
175#[derive(Copy, Clone, Default, Debug, PartialEq, Eq, Component, Reflect)]
176#[reflect(Component, Default, PartialEq)]
177pub struct Sensor;
178
179/// Custom mass-properties of a [`Collider`].
180#[derive(Copy, Clone, Debug, PartialEq, Component, Reflect)]
181#[reflect(Component, Default, PartialEq)]
182pub enum ColliderMassProperties {
183    /// The mass-properties are computed automatically from the collider’s shape and this density.
184    Density(f32),
185    /// The mass-properties are computed automatically from the collider’s shape and this mass.
186    Mass(f32),
187    /// The mass-properties of the collider are replaced by the ones specified here.
188    MassProperties(MassProperties),
189}
190
191impl Default for ColliderMassProperties {
192    fn default() -> Self {
193        Self::Density(1.0)
194    }
195}
196
197/// The mass-related properties of a [`Collider`], as computed by Rapier.
198///
199/// This component is inserted automatically with [`Collider`], and updated whenever the collider
200/// is created or its shape or [`ColliderMassProperties`] change. Modifying this component has no
201/// effect on the simulation; modify [`ColliderMassProperties`] instead.
202#[derive(Copy, Clone, Debug, Default, PartialEq, Component, Reflect)]
203#[reflect(Component, Default, PartialEq)]
204pub struct ReadColliderMassProperties {
205    /// The volume (in 3D) or area (in 2D) of the collider's shape.
206    pub volume: f32,
207    /// The density of the collider.
208    ///
209    /// If the collider's mass was set explicitly, this is the mass divided by the volume.
210    pub density: f32,
211    /// The mass of the collider.
212    pub mass: f32,
213    /// The mass properties of the collider, expressed in the collider's local-space.
214    pub local_mass_properties: MassProperties,
215}
216
217impl ReadColliderMassProperties {
218    /// Extracts the mass-related properties of a Rapier collider.
219    pub fn from_rapier(collider: &rapier::geometry::Collider) -> Self {
220        Self {
221            volume: collider.volume(),
222            density: collider.density(),
223            mass: collider.mass(),
224            local_mass_properties: MassProperties::from_rapier(collider.mass_properties()),
225        }
226    }
227}
228
229/// The friction affecting a [`Collider`].
230#[derive(Copy, Clone, Debug, PartialEq, Component, Reflect)]
231#[reflect(Component, Default, PartialEq)]
232pub struct Friction {
233    /// The friction coefficient of a collider.
234    ///
235    /// The greater the value, the stronger the friction forces will be.
236    /// Should be `>= 0`.
237    pub coefficient: f32,
238    /// The rule applied to combine the friction coefficients of two colliders in contact.
239    pub combine_rule: CoefficientCombineRule,
240}
241
242impl Default for Friction {
243    fn default() -> Self {
244        Self {
245            coefficient: 0.5,
246            combine_rule: CoefficientCombineRule::Average,
247        }
248    }
249}
250
251impl Friction {
252    /// Creates a [`Friction`] component from the given friction coefficient, and using the default
253    /// [`CoefficientCombineRule::Average`] coefficient combine rule.
254    pub const fn new(coefficient: f32) -> Self {
255        Self {
256            coefficient,
257            combine_rule: CoefficientCombineRule::Average,
258        }
259    }
260
261    /// Creates a [`Friction`] component from the given friction coefficient, and using the default
262    /// [`CoefficientCombineRule::Average`] coefficient combine rule.
263    pub const fn coefficient(coefficient: f32) -> Self {
264        Self {
265            coefficient,
266            combine_rule: CoefficientCombineRule::Average,
267        }
268    }
269}
270
271/// The restitution affecting a [`Collider`].
272#[derive(Copy, Clone, Debug, PartialEq, Component, Reflect)]
273#[reflect(Component, Default, PartialEq)]
274pub struct Restitution {
275    /// The restitution coefficient of a collider.
276    ///
277    /// The greater the value, the stronger the restitution forces will be.
278    /// Should be `>= 0`.
279    pub coefficient: f32,
280    /// The rule applied to combine the friction coefficients of two colliders in contact.
281    pub combine_rule: CoefficientCombineRule,
282}
283
284impl Restitution {
285    /// Creates a [`Restitution`] component from the given restitution coefficient, and using the default
286    /// [`CoefficientCombineRule::Average`] coefficient combine rule.
287    pub const fn new(coefficient: f32) -> Self {
288        Self {
289            coefficient,
290            combine_rule: CoefficientCombineRule::Average,
291        }
292    }
293
294    /// Creates a [`Restitution`] component from the given restitution coefficient, and using the default
295    /// [`CoefficientCombineRule::Average`] coefficient combine rule.
296    pub const fn coefficient(coefficient: f32) -> Self {
297        Self {
298            coefficient,
299            combine_rule: CoefficientCombineRule::Average,
300        }
301    }
302}
303
304impl Default for Restitution {
305    fn default() -> Self {
306        Self {
307            coefficient: 0.0,
308            combine_rule: CoefficientCombineRule::Average,
309        }
310    }
311}
312
313#[derive(Component, Reflect, Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
314#[reflect(Component, Default, Hash, PartialEq)]
315#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
316/// Flags affecting whether or not collision-detection happens between two colliders
317/// depending on the type of rigid-bodies they are attached to.
318pub struct ActiveCollisionTypes(u16);
319
320bitflags::bitflags! {
321    impl ActiveCollisionTypes: u16 {
322        /// Enable collision-detection between a collider attached to a dynamic body
323        /// and another collider attached to a dynamic body.
324        const DYNAMIC_DYNAMIC = 0b0000_0000_0000_0001;
325        /// Enable collision-detection between a collider attached to a dynamic body
326        /// and another collider attached to a kinematic body.
327        const DYNAMIC_KINEMATIC = 0b0000_0000_0000_1100;
328        /// Enable collision-detection between a collider attached to a dynamic body
329        /// and another collider attached to a fixed body (or not attached to any body).
330        const DYNAMIC_STATIC  = 0b0000_0000_0000_0010;
331        /// Enable collision-detection between a collider attached to a kinematic body
332        /// and another collider attached to a kinematic body.
333        const KINEMATIC_KINEMATIC = 0b1100_1100_0000_0000;
334
335        /// Enable collision-detection between a collider attached to a kinematic body
336        /// and another collider attached to a fixed body (or not attached to any body).
337        const KINEMATIC_STATIC = 0b0010_0010_0000_0000;
338
339        /// Enable collision-detection between a collider attached to a fixed body (or
340        /// not attached to any body) and another collider attached to a fixed body (or
341        /// not attached to any body).
342        const STATIC_STATIC = 0b0000_0000_0010_0000;
343    }
344}
345
346impl Default for ActiveCollisionTypes {
347    fn default() -> Self {
348        Self::DYNAMIC_DYNAMIC | Self::DYNAMIC_KINEMATIC | Self::DYNAMIC_STATIC
349    }
350}
351
352impl From<ActiveCollisionTypes> for rapier::geometry::ActiveCollisionTypes {
353    fn from(collision_types: ActiveCollisionTypes) -> rapier::geometry::ActiveCollisionTypes {
354        rapier::geometry::ActiveCollisionTypes::from_bits(collision_types.bits())
355            .expect("Internal error: invalid active events conversion.")
356    }
357}
358
359/// A bit mask identifying groups for interaction.
360#[derive(Component, Reflect, Copy, Clone, Debug, PartialEq, Eq, Hash)]
361#[reflect(Component, Default, Hash, PartialEq)]
362#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
363pub struct Group(u32);
364
365bitflags::bitflags! {
366    impl Group: u32 {
367        /// The group n°1.
368        const GROUP_1 = 1 << 0;
369        /// The group n°2.
370        const GROUP_2 = 1 << 1;
371        /// The group n°3.
372        const GROUP_3 = 1 << 2;
373        /// The group n°4.
374        const GROUP_4 = 1 << 3;
375        /// The group n°5.
376        const GROUP_5 = 1 << 4;
377        /// The group n°6.
378        const GROUP_6 = 1 << 5;
379        /// The group n°7.
380        const GROUP_7 = 1 << 6;
381        /// The group n°8.
382        const GROUP_8 = 1 << 7;
383        /// The group n°9.
384        const GROUP_9 = 1 << 8;
385        /// The group n°10.
386        const GROUP_10 = 1 << 9;
387        /// The group n°11.
388        const GROUP_11 = 1 << 10;
389        /// The group n°12.
390        const GROUP_12 = 1 << 11;
391        /// The group n°13.
392        const GROUP_13 = 1 << 12;
393        /// The group n°14.
394        const GROUP_14 = 1 << 13;
395        /// The group n°15.
396        const GROUP_15 = 1 << 14;
397        /// The group n°16.
398        const GROUP_16 = 1 << 15;
399        /// The group n°17.
400        const GROUP_17 = 1 << 16;
401        /// The group n°18.
402        const GROUP_18 = 1 << 17;
403        /// The group n°19.
404        const GROUP_19 = 1 << 18;
405        /// The group n°20.
406        const GROUP_20 = 1 << 19;
407        /// The group n°21.
408        const GROUP_21 = 1 << 20;
409        /// The group n°22.
410        const GROUP_22 = 1 << 21;
411        /// The group n°23.
412        const GROUP_23 = 1 << 22;
413        /// The group n°24.
414        const GROUP_24 = 1 << 23;
415        /// The group n°25.
416        const GROUP_25 = 1 << 24;
417        /// The group n°26.
418        const GROUP_26 = 1 << 25;
419        /// The group n°27.
420        const GROUP_27 = 1 << 26;
421        /// The group n°28.
422        const GROUP_28 = 1 << 27;
423        /// The group n°29.
424        const GROUP_29 = 1 << 28;
425        /// The group n°30.
426        const GROUP_30 = 1 << 29;
427        /// The group n°31.
428        const GROUP_31 = 1 << 30;
429        /// The group n°32.
430        const GROUP_32 = 1 << 31;
431
432        /// All of the groups.
433        const ALL = u32::MAX;
434        /// None of the groups.
435        const NONE = 0;
436    }
437}
438
439impl Default for Group {
440    fn default() -> Self {
441        Group::ALL
442    }
443}
444
445/// Specifies how the memberships and filters of two [`CollisionGroups`] (or two
446/// [`SolverGroups`]) are tested against each other.
447///
448/// If the two groups being tested have different test modes, [`InteractionTestMode::And`]
449/// takes priority.
450#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Hash, Reflect)]
451#[reflect(Default, Hash, PartialEq)]
452#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
453pub enum InteractionTestMode {
454    /// An interaction is allowed iff. the memberships of each group have at least one bit in
455    /// common with the filters of the other group.
456    #[default]
457    And,
458    /// An interaction is allowed iff. the memberships of either group have at least one bit in
459    /// common with the filters of the other group.
460    ///
461    /// This only applies if both groups use [`InteractionTestMode::Or`]; otherwise
462    /// [`InteractionTestMode::And`] is used.
463    Or,
464}
465
466impl From<InteractionTestMode> for RapierInteractionTestMode {
467    fn from(mode: InteractionTestMode) -> RapierInteractionTestMode {
468        match mode {
469            InteractionTestMode::And => RapierInteractionTestMode::And,
470            InteractionTestMode::Or => RapierInteractionTestMode::Or,
471        }
472    }
473}
474
475impl From<RapierInteractionTestMode> for InteractionTestMode {
476    fn from(mode: RapierInteractionTestMode) -> InteractionTestMode {
477        match mode {
478            RapierInteractionTestMode::And => InteractionTestMode::And,
479            RapierInteractionTestMode::Or => InteractionTestMode::Or,
480        }
481    }
482}
483
484/// Pairwise collision filtering using bit masks.
485///
486/// This filtering method is based on two 32-bit values:
487/// - The interaction groups memberships.
488/// - The interaction groups filter.
489///
490/// With the default [`InteractionTestMode::And`], an interaction is allowed between two filters
491/// `a` and `b` when two conditions are met simultaneously:
492/// - The groups membership of `a` has at least one bit set to `1` in common with the groups filter of `b`.
493/// - The groups membership of `b` has at least one bit set to `1` in common with the groups filter of `a`.
494///
495/// In other words, interactions are allowed between two filter iff. the following condition is met:
496/// ```ignore
497/// (self.memberships & rhs.filter) != 0 && (rhs.memberships & self.filter) != 0
498/// ```
499///
500/// If both filters use [`InteractionTestMode::Or`], meeting either condition is sufficient.
501#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Hash, Component, Reflect)]
502#[reflect(Component, Default, Hash, PartialEq)]
503#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
504pub struct CollisionGroups {
505    /// Groups memberships.
506    pub memberships: Group,
507    /// Groups filter.
508    pub filters: Group,
509    /// How the memberships and filters are tested against another [`CollisionGroups`].
510    #[cfg_attr(feature = "serde-serialize", serde(default))]
511    pub test_mode: InteractionTestMode,
512}
513
514impl CollisionGroups {
515    /// Creates a new collision-groups with the given membership masks and filter masks.
516    ///
517    /// The test mode is set to [`InteractionTestMode::And`].
518    pub const fn new(memberships: Group, filters: Group) -> Self {
519        Self {
520            memberships,
521            filters,
522            test_mode: InteractionTestMode::And,
523        }
524    }
525
526    /// Sets the test mode used to check interactions with another [`CollisionGroups`].
527    pub const fn with_test_mode(mut self, test_mode: InteractionTestMode) -> Self {
528        self.test_mode = test_mode;
529        self
530    }
531}
532
533impl From<CollisionGroups> for InteractionGroups {
534    fn from(collision_groups: CollisionGroups) -> InteractionGroups {
535        InteractionGroups {
536            memberships: rapier::geometry::Group::from_bits(collision_groups.memberships.bits())
537                .unwrap(),
538            filter: rapier::geometry::Group::from_bits(collision_groups.filters.bits()).unwrap(),
539            test_mode: collision_groups.test_mode.into(),
540        }
541    }
542}
543
544impl From<InteractionGroups> for CollisionGroups {
545    fn from(groups: InteractionGroups) -> CollisionGroups {
546        CollisionGroups {
547            memberships: Group::from_bits_retain(groups.memberships.bits()),
548            filters: Group::from_bits_retain(groups.filter.bits()),
549            test_mode: groups.test_mode.into(),
550        }
551    }
552}
553
554/// Pairwise constraints resolution filtering using bit masks.
555///
556/// This follows the same rules as the `CollisionGroups`.
557#[derive(Copy, Clone, Default, Debug, PartialEq, Eq, Hash, Component, Reflect)]
558#[reflect(Component, Default, Hash, PartialEq)]
559#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
560pub struct SolverGroups {
561    /// Groups memberships.
562    pub memberships: Group,
563    /// Groups filter.
564    pub filters: Group,
565    /// How the memberships and filters are tested against another [`SolverGroups`].
566    #[cfg_attr(feature = "serde-serialize", serde(default))]
567    pub test_mode: InteractionTestMode,
568}
569
570impl SolverGroups {
571    /// Creates a new solver-groups with the given membership masks and filter masks.
572    ///
573    /// The test mode is set to [`InteractionTestMode::And`].
574    pub const fn new(memberships: Group, filters: Group) -> Self {
575        Self {
576            memberships,
577            filters,
578            test_mode: InteractionTestMode::And,
579        }
580    }
581
582    /// Sets the test mode used to check interactions with another [`SolverGroups`].
583    pub const fn with_test_mode(mut self, test_mode: InteractionTestMode) -> Self {
584        self.test_mode = test_mode;
585        self
586    }
587}
588
589impl From<SolverGroups> for InteractionGroups {
590    fn from(solver_groups: SolverGroups) -> InteractionGroups {
591        InteractionGroups {
592            memberships: rapier::geometry::Group::from_bits(solver_groups.memberships.bits())
593                .unwrap(),
594            filter: rapier::geometry::Group::from_bits(solver_groups.filters.bits()).unwrap(),
595            test_mode: solver_groups.test_mode.into(),
596        }
597    }
598}
599
600impl From<InteractionGroups> for SolverGroups {
601    fn from(groups: InteractionGroups) -> SolverGroups {
602        SolverGroups {
603            memberships: Group::from_bits_retain(groups.memberships.bits()),
604            filters: Group::from_bits_retain(groups.filter.bits()),
605            test_mode: groups.test_mode.into(),
606        }
607    }
608}
609
610#[derive(Default, Component, Reflect, Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
611#[reflect(Component, Default)]
612#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
613/// Flags affecting the behavior of the constraints solver for a given contact manifold.
614pub struct ActiveHooks(u32);
615
616bitflags::bitflags! {
617    impl ActiveHooks: u32 {
618        /// If set, Rapier will call `PhysicsHooks::filter_contact_pair` whenever relevant.
619        const FILTER_CONTACT_PAIRS = 0b0001;
620        /// If set, Rapier will call `PhysicsHooks::filter_intersection_pair` whenever relevant.
621        const FILTER_INTERSECTION_PAIR = 0b0010;
622        /// If set, Rapier will call `PhysicsHooks::modify_solver_contact` whenever relevant.
623        const MODIFY_SOLVER_CONTACTS = 0b0100;
624    }
625}
626
627impl From<ActiveHooks> for rapier::pipeline::ActiveHooks {
628    fn from(active_hooks: ActiveHooks) -> rapier::pipeline::ActiveHooks {
629        rapier::pipeline::ActiveHooks::from_bits(active_hooks.bits())
630            .expect("Internal error: invalid active events conversion.")
631    }
632}
633
634#[derive(Default, Component, Reflect, Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
635#[reflect(Component, Default)]
636#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
637/// Flags affecting the events generated for this [`Collider`].
638pub struct ActiveEvents(u32);
639
640bitflags::bitflags! {
641    impl ActiveEvents: u32 {
642        /// If set, Rapier will call `EventHandler::handle_collision_event`
643        /// whenever relevant for this [`Collider`].
644        const COLLISION_EVENTS = 0b0001;
645        /// If set, Rapier will call `EventHandler::handle_contact_force_event`
646        /// whenever relevant for this [`Collider`].
647        const CONTACT_FORCE_EVENTS = 0b0010;
648    }
649}
650
651impl From<ActiveEvents> for rapier::pipeline::ActiveEvents {
652    fn from(active_events: ActiveEvents) -> rapier::pipeline::ActiveEvents {
653        rapier::pipeline::ActiveEvents::from_bits(active_events.bits())
654            .expect("Internal error: invalid active events conversion.")
655    }
656}
657
658/// The total force magnitude beyond which a [`ContactForceEvent`] can be emitted.
659///
660/// This requires that the [`ActiveEvents::CONTACT_FORCE_EVENTS`] flag is set on the
661/// entity.
662#[derive(Copy, Clone, PartialEq, Component, Reflect)]
663#[reflect(Component, Default)]
664#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
665pub struct ContactForceEventThreshold(pub f32);
666
667impl Default for ContactForceEventThreshold {
668    fn default() -> Self {
669        Self(f32::MAX)
670    }
671}
672
673/// Sets the contact skin of the collider.
674///
675/// The contact skin acts as if the collider was enlarged with a skin of width `skin_thickness`
676/// around it, keeping objects further apart when colliding.
677///
678/// A non-zero contact skin can increase performance, and in some cases, stability. However
679/// it creates a small gap between colliding object (equal to the sum of their skin). If the
680/// skin is sufficiently small, this might not be visually significant or can be hidden by the
681/// rendering assets.
682#[derive(Copy, Clone, PartialEq, Default, Component, Reflect)]
683#[reflect(Component, Default)]
684#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
685pub struct ContactSkin(pub f32);
686
687/// Component which will be filled (if present) with a list of entities with which the current
688/// entity is currently in contact.
689///
690/// This currently only updates when on an entity with a `Collider`, and if the
691/// [`ActiveEvents::COLLISION_EVENTS`] is set on this entity or the entity it
692/// collided with.
693#[derive(Component, Default, Reflect)]
694#[reflect(Component, Default)]
695pub struct CollidingEntities(pub(crate) HashSet<Entity>);
696
697impl CollidingEntities {
698    /// Returns the number of colliding entities.
699    #[must_use]
700    pub fn len(&self) -> usize {
701        self.0.len()
702    }
703
704    /// Returns `true` if there is no colliding entities.
705    #[must_use]
706    pub fn is_empty(&self) -> bool {
707        self.0.is_empty()
708    }
709
710    /// Returns `true` if the collisions contains the specified entity.
711    #[must_use]
712    pub fn contains(&self, entity: Entity) -> bool {
713        self.0.contains(&entity)
714    }
715
716    /// An iterator visiting all colliding entities in arbitrary order.
717    pub fn iter(&self) -> impl Iterator<Item = Entity> + '_ {
718        self.0.iter().copied()
719    }
720}
721
722/// Indicates whether or not the collider is disabled explicitly by the user.
723#[derive(Copy, Clone, Default, Debug, PartialEq, Eq, Component, Reflect)]
724#[reflect(Component, Default, PartialEq)]
725pub struct ColliderDisabled;
726
727/// We restrict the scaling increment to 1.0e-4, to avoid numerical jitter
728/// due to the extraction of scaling factor from the GlobalTransform matrix.
729pub fn get_snapped_scale(scale: Vect) -> Vect {
730    fn snap_value(new: f32) -> f32 {
731        const PRECISION: f32 = 1.0e4;
732        (new * PRECISION).round() / PRECISION
733    }
734
735    Vect {
736        x: snap_value(scale.x),
737        y: snap_value(scale.y),
738        #[cfg(feature = "dim3")]
739        z: snap_value(scale.z),
740    }
741}