1use std::fmt;
2
3#[cfg(all(feature = "dim3", feature = "async-collider"))]
4use {
5 crate::geometry::{TriMeshFlags, VHACDParameters},
6 bevy::platform::collections::HashMap,
7};
8
9use bevy::prelude::*;
10
11use bevy::platform::collections::HashSet;
12use rapier::geometry::Shape;
13use rapier::prelude::{ColliderHandle, InteractionGroups, SharedShape};
14
15use crate::dynamics::{CoefficientCombineRule, MassProperties};
16use crate::math::Vect;
17
18#[cfg(doc)]
19use rapier::{dynamics::RigidBody, geometry::ContactForceEvent};
20
21#[derive(Copy, Clone, Debug, Component)]
23pub struct RapierColliderHandle(pub ColliderHandle);
24
25#[cfg(all(feature = "dim3", feature = "async-collider"))]
27#[derive(Component, Debug, Clone, Default)]
28pub struct AsyncCollider(pub ComputedColliderShape);
29
30#[cfg(all(feature = "dim3", feature = "async-collider"))]
32#[derive(Component, Debug, Clone)]
33pub struct AsyncSceneCollider {
34 pub shape: Option<ComputedColliderShape>,
37 pub named_shapes: HashMap<String, Option<ComputedColliderShape>>,
40}
41
42#[cfg(all(feature = "dim3", feature = "async-collider"))]
43impl Default for AsyncSceneCollider {
44 fn default() -> Self {
45 Self {
46 shape: Some(Default::default()),
47 named_shapes: Default::default(),
48 }
49 }
50}
51
52#[cfg(all(feature = "dim3", feature = "async-collider"))]
54#[derive(Debug, Clone)]
55pub enum ComputedColliderShape {
56 TriMesh(TriMeshFlags),
58 ConvexHull,
60 ConvexDecomposition(VHACDParameters),
62}
63
64#[cfg(all(feature = "dim3", feature = "async-collider"))]
65impl Default for ComputedColliderShape {
66 fn default() -> Self {
67 Self::TriMesh(TriMeshFlags::MERGE_DUPLICATE_VERTICES)
68 }
69}
70
71#[derive(Component, Clone)] #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
89pub struct Collider {
90 pub raw: SharedShape,
92 pub(crate) unscaled: SharedShape,
93 pub(crate) scale: Vect,
94}
95
96impl From<SharedShape> for Collider {
97 fn from(shared_shape: SharedShape) -> Collider {
98 Collider {
99 raw: shared_shape.clone(),
100 unscaled: shared_shape,
101 scale: Vect::ONE,
102 }
103 }
104}
105
106impl<'a> From<&'a Collider> for &'a dyn Shape {
107 fn from(collider: &'a Collider) -> &'a dyn Shape {
108 &*collider.raw
109 }
110}
111
112impl fmt::Debug for Collider {
113 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
114 self.as_typed_shape().fmt(f)
115 }
116}
117
118#[derive(Copy, Clone, Debug, PartialEq, Component, Reflect)]
120pub enum ColliderScale {
121 Relative(Vect),
124 Absolute(Vect),
126}
127
128#[derive(Copy, Clone, Default, Debug, PartialEq, Eq, Component, Reflect)]
130#[reflect(Component, Default, PartialEq)]
131pub struct Sensor;
132
133#[derive(Copy, Clone, Debug, PartialEq, Component, Reflect)]
135#[reflect(Component, Default, PartialEq)]
136pub enum ColliderMassProperties {
137 Density(f32),
139 Mass(f32),
141 MassProperties(MassProperties),
143}
144
145impl Default for ColliderMassProperties {
146 fn default() -> Self {
147 Self::Density(1.0)
148 }
149}
150
151#[derive(Copy, Clone, Debug, PartialEq, Component, Reflect)]
153#[reflect(Component, Default, PartialEq)]
154pub struct Friction {
155 pub coefficient: f32,
160 pub combine_rule: CoefficientCombineRule,
162}
163
164impl Default for Friction {
165 fn default() -> Self {
166 Self {
167 coefficient: 0.5,
168 combine_rule: CoefficientCombineRule::Average,
169 }
170 }
171}
172
173impl Friction {
174 pub const fn new(coefficient: f32) -> Self {
177 Self {
178 coefficient,
179 combine_rule: CoefficientCombineRule::Average,
180 }
181 }
182
183 pub const fn coefficient(coefficient: f32) -> Self {
186 Self {
187 coefficient,
188 combine_rule: CoefficientCombineRule::Average,
189 }
190 }
191}
192
193#[derive(Copy, Clone, Debug, PartialEq, Component, Reflect)]
195#[reflect(Component, Default, PartialEq)]
196pub struct Restitution {
197 pub coefficient: f32,
202 pub combine_rule: CoefficientCombineRule,
204}
205
206impl Restitution {
207 pub const fn new(coefficient: f32) -> Self {
210 Self {
211 coefficient,
212 combine_rule: CoefficientCombineRule::Average,
213 }
214 }
215
216 pub const fn coefficient(coefficient: f32) -> Self {
219 Self {
220 coefficient,
221 combine_rule: CoefficientCombineRule::Average,
222 }
223 }
224}
225
226impl Default for Restitution {
227 fn default() -> Self {
228 Self {
229 coefficient: 0.0,
230 combine_rule: CoefficientCombineRule::Average,
231 }
232 }
233}
234
235#[derive(Component, Reflect, Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
236#[reflect(Component, Default, Hash, PartialEq)]
237#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
238pub struct ActiveCollisionTypes(u16);
241
242bitflags::bitflags! {
243 impl ActiveCollisionTypes: u16 {
244 const DYNAMIC_DYNAMIC = 0b0000_0000_0000_0001;
247 const DYNAMIC_KINEMATIC = 0b0000_0000_0000_1100;
250 const DYNAMIC_STATIC = 0b0000_0000_0000_0010;
253 const KINEMATIC_KINEMATIC = 0b1100_1100_0000_0000;
256
257 const KINEMATIC_STATIC = 0b0010_0010_0000_0000;
260
261 const STATIC_STATIC = 0b0000_0000_0010_0000;
265 }
266}
267
268impl Default for ActiveCollisionTypes {
269 fn default() -> Self {
270 Self::DYNAMIC_DYNAMIC | Self::DYNAMIC_KINEMATIC | Self::DYNAMIC_STATIC
271 }
272}
273
274impl From<ActiveCollisionTypes> for rapier::geometry::ActiveCollisionTypes {
275 fn from(collision_types: ActiveCollisionTypes) -> rapier::geometry::ActiveCollisionTypes {
276 rapier::geometry::ActiveCollisionTypes::from_bits(collision_types.bits())
277 .expect("Internal error: invalid active events conversion.")
278 }
279}
280
281#[derive(Component, Reflect, Copy, Clone, Debug, PartialEq, Eq, Hash)]
283#[reflect(Component, Default, Hash, PartialEq)]
284#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
285pub struct Group(u32);
286
287bitflags::bitflags! {
288 impl Group: u32 {
289 const GROUP_1 = 1 << 0;
291 const GROUP_2 = 1 << 1;
293 const GROUP_3 = 1 << 2;
295 const GROUP_4 = 1 << 3;
297 const GROUP_5 = 1 << 4;
299 const GROUP_6 = 1 << 5;
301 const GROUP_7 = 1 << 6;
303 const GROUP_8 = 1 << 7;
305 const GROUP_9 = 1 << 8;
307 const GROUP_10 = 1 << 9;
309 const GROUP_11 = 1 << 10;
311 const GROUP_12 = 1 << 11;
313 const GROUP_13 = 1 << 12;
315 const GROUP_14 = 1 << 13;
317 const GROUP_15 = 1 << 14;
319 const GROUP_16 = 1 << 15;
321 const GROUP_17 = 1 << 16;
323 const GROUP_18 = 1 << 17;
325 const GROUP_19 = 1 << 18;
327 const GROUP_20 = 1 << 19;
329 const GROUP_21 = 1 << 20;
331 const GROUP_22 = 1 << 21;
333 const GROUP_23 = 1 << 22;
335 const GROUP_24 = 1 << 23;
337 const GROUP_25 = 1 << 24;
339 const GROUP_26 = 1 << 25;
341 const GROUP_27 = 1 << 26;
343 const GROUP_28 = 1 << 27;
345 const GROUP_29 = 1 << 28;
347 const GROUP_30 = 1 << 29;
349 const GROUP_31 = 1 << 30;
351 const GROUP_32 = 1 << 31;
353
354 const ALL = u32::MAX;
356 const NONE = 0;
358 }
359}
360
361impl Default for Group {
362 fn default() -> Self {
363 Group::ALL
364 }
365}
366
367#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Hash, Component, Reflect)]
383#[reflect(Component, Default, Hash, PartialEq)]
384#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
385pub struct CollisionGroups {
386 pub memberships: Group,
388 pub filters: Group,
390}
391
392impl CollisionGroups {
393 pub const fn new(memberships: Group, filters: Group) -> Self {
395 Self {
396 memberships,
397 filters,
398 }
399 }
400}
401
402impl From<CollisionGroups> for InteractionGroups {
403 fn from(collision_groups: CollisionGroups) -> InteractionGroups {
404 InteractionGroups {
405 memberships: rapier::geometry::Group::from_bits(collision_groups.memberships.bits())
406 .unwrap(),
407 filter: rapier::geometry::Group::from_bits(collision_groups.filters.bits()).unwrap(),
408 }
409 }
410}
411
412#[derive(Copy, Clone, Default, Debug, PartialEq, Eq, Hash, Component, Reflect)]
416#[reflect(Component, Default, Hash, PartialEq)]
417#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
418pub struct SolverGroups {
419 pub memberships: Group,
421 pub filters: Group,
423}
424
425impl SolverGroups {
426 pub const fn new(memberships: Group, filters: Group) -> Self {
428 Self {
429 memberships,
430 filters,
431 }
432 }
433}
434
435impl From<SolverGroups> for InteractionGroups {
436 fn from(solver_groups: SolverGroups) -> InteractionGroups {
437 InteractionGroups {
438 memberships: rapier::geometry::Group::from_bits(solver_groups.memberships.bits())
439 .unwrap(),
440 filter: rapier::geometry::Group::from_bits(solver_groups.filters.bits()).unwrap(),
441 }
442 }
443}
444
445#[derive(Default, Component, Reflect, Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
446#[reflect(Component, Default)]
447#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
448pub struct ActiveHooks(u32);
450
451bitflags::bitflags! {
452 impl ActiveHooks: u32 {
453 const FILTER_CONTACT_PAIRS = 0b0001;
455 const FILTER_INTERSECTION_PAIR = 0b0010;
457 const MODIFY_SOLVER_CONTACTS = 0b0100;
459 }
460}
461
462impl From<ActiveHooks> for rapier::pipeline::ActiveHooks {
463 fn from(active_hooks: ActiveHooks) -> rapier::pipeline::ActiveHooks {
464 rapier::pipeline::ActiveHooks::from_bits(active_hooks.bits())
465 .expect("Internal error: invalid active events conversion.")
466 }
467}
468
469#[derive(Default, Component, Reflect, Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
470#[reflect(Component, Default)]
471#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
472pub struct ActiveEvents(u32);
474
475bitflags::bitflags! {
476 impl ActiveEvents: u32 {
477 const COLLISION_EVENTS = 0b0001;
480 const CONTACT_FORCE_EVENTS = 0b0010;
483 }
484}
485
486impl From<ActiveEvents> for rapier::pipeline::ActiveEvents {
487 fn from(active_events: ActiveEvents) -> rapier::pipeline::ActiveEvents {
488 rapier::pipeline::ActiveEvents::from_bits(active_events.bits())
489 .expect("Internal error: invalid active events conversion.")
490 }
491}
492
493#[derive(Copy, Clone, PartialEq, Component, Reflect)]
498#[reflect(Component, Default)]
499#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
500pub struct ContactForceEventThreshold(pub f32);
501
502impl Default for ContactForceEventThreshold {
503 fn default() -> Self {
504 Self(f32::MAX)
505 }
506}
507
508#[derive(Copy, Clone, PartialEq, Default, Component, Reflect)]
518#[reflect(Component, Default)]
519#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
520pub struct ContactSkin(pub f32);
521
522#[derive(Component, Default, Reflect)]
529#[reflect(Component, Default)]
530pub struct CollidingEntities(pub(crate) HashSet<Entity>);
531
532impl CollidingEntities {
533 #[must_use]
535 pub fn len(&self) -> usize {
536 self.0.len()
537 }
538
539 #[must_use]
541 pub fn is_empty(&self) -> bool {
542 self.0.is_empty()
543 }
544
545 #[must_use]
547 pub fn contains(&self, entity: Entity) -> bool {
548 self.0.contains(&entity)
549 }
550
551 pub fn iter(&self) -> impl Iterator<Item = Entity> + '_ {
553 self.0.iter().copied()
554 }
555}
556
557#[derive(Copy, Clone, Default, Debug, PartialEq, Eq, Component, Reflect)]
559#[reflect(Component, Default, PartialEq)]
560pub struct ColliderDisabled;
561
562pub fn get_snapped_scale(scale: Vect) -> Vect {
565 fn snap_value(new: f32) -> f32 {
566 const PRECISION: f32 = 1.0e4;
567 (new * PRECISION).round() / PRECISION
568 }
569
570 Vect {
571 x: snap_value(scale.x),
572 y: snap_value(scale.y),
573 #[cfg(feature = "dim3")]
574 z: snap_value(scale.z),
575 }
576}