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#[derive(Copy, Clone, Debug, Component)]
27pub struct RapierColliderHandle(pub ColliderHandle);
28
29#[cfg(all(feature = "dim3", feature = "async-collider"))]
31#[derive(Component, Debug, Clone, Default)]
32pub struct AsyncCollider(pub ComputedColliderShape);
33
34#[cfg(all(feature = "dim3", feature = "async-collider"))]
36#[derive(Component, Debug, Clone)]
37pub struct AsyncSceneCollider {
38 pub shape: Option<ComputedColliderShape>,
41 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#[cfg(all(feature = "dim3", feature = "async-collider"))]
58#[derive(Debug, Clone)]
59pub enum ComputedColliderShape {
60 TriMesh(TriMeshFlags),
62 ConvexHull,
64 ConvexDecomposition(VHACDParameters),
66 Voxels {
68 voxel_size: Real,
70 fill_mode: FillMode,
73 },
74 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#[derive(Component, Clone)] #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
105#[require(ReadColliderMassProperties)]
106pub struct Collider {
107 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
129pub trait AsShape {
136 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#[derive(Copy, Clone, Debug, PartialEq, Component, Reflect)]
166pub enum ColliderScale {
167 Relative(Vect),
170 Absolute(Vect),
172}
173
174#[derive(Copy, Clone, Default, Debug, PartialEq, Eq, Component, Reflect)]
176#[reflect(Component, Default, PartialEq)]
177pub struct Sensor;
178
179#[derive(Copy, Clone, Debug, PartialEq, Component, Reflect)]
181#[reflect(Component, Default, PartialEq)]
182pub enum ColliderMassProperties {
183 Density(f32),
185 Mass(f32),
187 MassProperties(MassProperties),
189}
190
191impl Default for ColliderMassProperties {
192 fn default() -> Self {
193 Self::Density(1.0)
194 }
195}
196
197#[derive(Copy, Clone, Debug, Default, PartialEq, Component, Reflect)]
203#[reflect(Component, Default, PartialEq)]
204pub struct ReadColliderMassProperties {
205 pub volume: f32,
207 pub density: f32,
211 pub mass: f32,
213 pub local_mass_properties: MassProperties,
215}
216
217impl ReadColliderMassProperties {
218 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#[derive(Copy, Clone, Debug, PartialEq, Component, Reflect)]
231#[reflect(Component, Default, PartialEq)]
232pub struct Friction {
233 pub coefficient: f32,
238 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 pub const fn new(coefficient: f32) -> Self {
255 Self {
256 coefficient,
257 combine_rule: CoefficientCombineRule::Average,
258 }
259 }
260
261 pub const fn coefficient(coefficient: f32) -> Self {
264 Self {
265 coefficient,
266 combine_rule: CoefficientCombineRule::Average,
267 }
268 }
269}
270
271#[derive(Copy, Clone, Debug, PartialEq, Component, Reflect)]
273#[reflect(Component, Default, PartialEq)]
274pub struct Restitution {
275 pub coefficient: f32,
280 pub combine_rule: CoefficientCombineRule,
282}
283
284impl Restitution {
285 pub const fn new(coefficient: f32) -> Self {
288 Self {
289 coefficient,
290 combine_rule: CoefficientCombineRule::Average,
291 }
292 }
293
294 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))]
316pub struct ActiveCollisionTypes(u16);
319
320bitflags::bitflags! {
321 impl ActiveCollisionTypes: u16 {
322 const DYNAMIC_DYNAMIC = 0b0000_0000_0000_0001;
325 const DYNAMIC_KINEMATIC = 0b0000_0000_0000_1100;
328 const DYNAMIC_STATIC = 0b0000_0000_0000_0010;
331 const KINEMATIC_KINEMATIC = 0b1100_1100_0000_0000;
334
335 const KINEMATIC_STATIC = 0b0010_0010_0000_0000;
338
339 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#[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 const GROUP_1 = 1 << 0;
369 const GROUP_2 = 1 << 1;
371 const GROUP_3 = 1 << 2;
373 const GROUP_4 = 1 << 3;
375 const GROUP_5 = 1 << 4;
377 const GROUP_6 = 1 << 5;
379 const GROUP_7 = 1 << 6;
381 const GROUP_8 = 1 << 7;
383 const GROUP_9 = 1 << 8;
385 const GROUP_10 = 1 << 9;
387 const GROUP_11 = 1 << 10;
389 const GROUP_12 = 1 << 11;
391 const GROUP_13 = 1 << 12;
393 const GROUP_14 = 1 << 13;
395 const GROUP_15 = 1 << 14;
397 const GROUP_16 = 1 << 15;
399 const GROUP_17 = 1 << 16;
401 const GROUP_18 = 1 << 17;
403 const GROUP_19 = 1 << 18;
405 const GROUP_20 = 1 << 19;
407 const GROUP_21 = 1 << 20;
409 const GROUP_22 = 1 << 21;
411 const GROUP_23 = 1 << 22;
413 const GROUP_24 = 1 << 23;
415 const GROUP_25 = 1 << 24;
417 const GROUP_26 = 1 << 25;
419 const GROUP_27 = 1 << 26;
421 const GROUP_28 = 1 << 27;
423 const GROUP_29 = 1 << 28;
425 const GROUP_30 = 1 << 29;
427 const GROUP_31 = 1 << 30;
429 const GROUP_32 = 1 << 31;
431
432 const ALL = u32::MAX;
434 const NONE = 0;
436 }
437}
438
439impl Default for Group {
440 fn default() -> Self {
441 Group::ALL
442 }
443}
444
445#[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 #[default]
457 And,
458 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#[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 pub memberships: Group,
507 pub filters: Group,
509 #[cfg_attr(feature = "serde-serialize", serde(default))]
511 pub test_mode: InteractionTestMode,
512}
513
514impl CollisionGroups {
515 pub const fn new(memberships: Group, filters: Group) -> Self {
519 Self {
520 memberships,
521 filters,
522 test_mode: InteractionTestMode::And,
523 }
524 }
525
526 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#[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 pub memberships: Group,
563 pub filters: Group,
565 #[cfg_attr(feature = "serde-serialize", serde(default))]
567 pub test_mode: InteractionTestMode,
568}
569
570impl SolverGroups {
571 pub const fn new(memberships: Group, filters: Group) -> Self {
575 Self {
576 memberships,
577 filters,
578 test_mode: InteractionTestMode::And,
579 }
580 }
581
582 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))]
613pub struct ActiveHooks(u32);
615
616bitflags::bitflags! {
617 impl ActiveHooks: u32 {
618 const FILTER_CONTACT_PAIRS = 0b0001;
620 const FILTER_INTERSECTION_PAIR = 0b0010;
622 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))]
637pub struct ActiveEvents(u32);
639
640bitflags::bitflags! {
641 impl ActiveEvents: u32 {
642 const COLLISION_EVENTS = 0b0001;
645 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#[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#[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#[derive(Component, Default, Reflect)]
694#[reflect(Component, Default)]
695pub struct CollidingEntities(pub(crate) HashSet<Entity>);
696
697impl CollidingEntities {
698 #[must_use]
700 pub fn len(&self) -> usize {
701 self.0.len()
702 }
703
704 #[must_use]
706 pub fn is_empty(&self) -> bool {
707 self.0.is_empty()
708 }
709
710 #[must_use]
712 pub fn contains(&self, entity: Entity) -> bool {
713 self.0.contains(&entity)
714 }
715
716 pub fn iter(&self) -> impl Iterator<Item = Entity> + '_ {
718 self.0.iter().copied()
719 }
720}
721
722#[derive(Copy, Clone, Default, Debug, PartialEq, Eq, Component, Reflect)]
724#[reflect(Component, Default, PartialEq)]
725pub struct ColliderDisabled;
726
727pub 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}