1use crate::core::math::Vec2;
45use crate::ecs::Component;
46
47#[repr(u8)]
61#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
62pub enum RigidBodyType {
63 Dynamic = 0,
72
73 Kinematic = 1,
82
83 Static = 2,
92}
93
94impl Default for RigidBodyType {
95 fn default() -> Self {
97 Self::Dynamic
98 }
99}
100
101impl RigidBodyType {
102 #[inline]
104 pub fn is_affected_by_gravity(self) -> bool {
105 matches!(self, RigidBodyType::Dynamic)
106 }
107
108 #[inline]
110 pub fn is_affected_by_forces(self) -> bool {
111 matches!(self, RigidBodyType::Dynamic)
112 }
113
114 #[inline]
116 pub fn can_move(self) -> bool {
117 !matches!(self, RigidBodyType::Static)
118 }
119
120 #[inline]
122 pub fn responds_to_collisions(self) -> bool {
123 matches!(self, RigidBodyType::Dynamic)
124 }
125
126 pub fn name(self) -> &'static str {
128 match self {
129 RigidBodyType::Dynamic => "Dynamic",
130 RigidBodyType::Kinematic => "Kinematic",
131 RigidBodyType::Static => "Static",
132 }
133 }
134}
135
136impl std::fmt::Display for RigidBodyType {
137 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
138 write!(f, "{}", self.name())
139 }
140}
141
142#[derive(Clone, Copy, Debug, PartialEq)]
193pub struct RigidBody {
194 pub body_type: RigidBodyType,
196
197 pub linear_velocity: Vec2,
199
200 pub angular_velocity: f32,
202
203 pub linear_damping: f32,
206
207 pub angular_damping: f32,
209
210 pub mass: f32,
213
214 pub inverse_mass: f32,
217
218 pub inertia: f32,
221
222 pub inverse_inertia: f32,
225
226 pub restitution: f32,
231
232 pub friction: f32,
236
237 pub gravity_scale: f32,
242
243 flags: u8,
245
246 sleep_time: f32,
249}
250
251struct RigidBodyFlags;
257
258impl RigidBodyFlags {
259 const SLEEPING: u8 = 1 << 0;
261 const CAN_SLEEP: u8 = 1 << 1;
263 const CONTINUOUS_CD: u8 = 1 << 2;
265 const FIXED_ROTATION: u8 = 1 << 3;
267}
268
269impl Default for RigidBody {
274 fn default() -> Self {
276 Self::dynamic()
277 }
278}
279
280impl RigidBody {
281 pub fn new(body_type: RigidBodyType) -> Self {
299 let (mass, inverse_mass) = if body_type == RigidBodyType::Dynamic {
300 (1.0, 1.0)
301 } else {
302 (0.0, 0.0) };
304
305 Self {
306 body_type,
307 linear_velocity: Vec2::zero(),
308 angular_velocity: 0.0,
309 linear_damping: 0.01, angular_damping: 0.01,
311 mass,
312 inverse_mass,
313 inertia: 1.0,
314 inverse_inertia: if body_type == RigidBodyType::Dynamic {
315 1.0
316 } else {
317 0.0
318 },
319 restitution: 0.0, friction: 0.5, gravity_scale: 1.0, flags: RigidBodyFlags::CAN_SLEEP, sleep_time: 0.0,
324 }
325 }
326
327 #[inline]
338 pub fn dynamic() -> Self {
339 Self::new(RigidBodyType::Dynamic)
340 }
341
342 #[inline]
354 pub fn kinematic() -> Self {
355 Self::new(RigidBodyType::Kinematic)
356 }
357
358 #[inline]
368 pub fn static_body() -> Self {
369 Self::new(RigidBodyType::Static)
370 }
371
372 pub fn with_velocity(mut self, velocity: Vec2) -> Self {
378 self.linear_velocity = velocity;
379 self
380 }
381
382 pub fn with_angular_velocity(mut self, angular_velocity: f32) -> Self {
384 self.angular_velocity = angular_velocity;
385 self
386 }
387
388 pub fn with_mass(mut self, mass: f32) -> Self {
394 assert!(
395 mass > 0.0 && mass.is_finite(),
396 "Mass must be positive and finite"
397 );
398 self.mass = mass;
399 self.inverse_mass = 1.0 / mass;
400 self
401 }
402
403 pub fn with_linear_damping(mut self, damping: f32) -> Self {
405 self.linear_damping = damping.max(0.0);
406 self
407 }
408
409 pub fn with_angular_damping(mut self, damping: f32) -> Self {
411 self.angular_damping = damping.max(0.0);
412 self
413 }
414
415 pub fn with_restitution(mut self, restitution: f32) -> Self {
417 self.restitution = restitution.max(0.0);
418 self
419 }
420
421 pub fn with_friction(mut self, friction: f32) -> Self {
423 self.friction = friction.max(0.0);
424 self
425 }
426
427 pub fn with_gravity_scale(mut self, scale: f32) -> Self {
429 self.gravity_scale = scale;
430 self
431 }
432
433 pub fn with_can_sleep(mut self, can_sleep: bool) -> Self {
435 if can_sleep {
436 self.flags |= RigidBodyFlags::CAN_SLEEP;
437 } else {
438 self.flags &= !RigidBodyFlags::CAN_SLEEP;
439 }
440 self
441 }
442
443 pub fn with_continuous_cd(mut self, enabled: bool) -> Self {
445 if enabled {
446 self.flags |= RigidBodyFlags::CONTINUOUS_CD;
447 } else {
448 self.flags &= !RigidBodyFlags::CONTINUOUS_CD;
449 }
450 self
451 }
452
453 pub fn with_fixed_rotation(mut self, fixed: bool) -> Self {
455 if fixed {
456 self.flags |= RigidBodyFlags::FIXED_ROTATION;
457 self.angular_velocity = 0.0;
458 self.inertia = 0.0;
459 self.inverse_inertia = 0.0;
460 } else {
461 self.flags &= !RigidBodyFlags::FIXED_ROTATION;
462 }
463 self
464 }
465
466 #[inline]
472 pub fn body_type(&self) -> RigidBodyType {
473 self.body_type
474 }
475
476 #[inline]
478 pub fn is_dynamic(&self) -> bool {
479 self.body_type == RigidBodyType::Dynamic
480 }
481
482 #[inline]
484 pub fn is_kinematic(&self) -> bool {
485 self.body_type == RigidBodyType::Kinematic
486 }
487
488 #[inline]
490 pub fn is_static(&self) -> bool {
491 self.body_type == RigidBodyType::Static
492 }
493
494 #[inline]
496 pub fn is_sleeping(&self) -> bool {
497 self.flags & RigidBodyFlags::SLEEPING != 0
498 }
499
500 #[inline]
502 pub fn can_sleep(&self) -> bool {
503 self.flags & RigidBodyFlags::CAN_SLEEP != 0
504 }
505
506 #[inline]
508 pub fn has_continuous_cd(&self) -> bool {
509 self.flags & RigidBodyFlags::CONTINUOUS_CD != 0
510 }
511
512 #[inline]
514 pub fn has_fixed_rotation(&self) -> bool {
515 self.flags & RigidBodyFlags::FIXED_ROTATION != 0
516 }
517
518 #[inline]
520 pub fn sleep_time(&self) -> f32 {
521 self.sleep_time
522 }
523
524 #[inline]
526 pub fn linear_speed(&self) -> f32 {
527 self.linear_velocity.length()
528 }
529
530 #[inline]
532 pub fn linear_speed_squared(&self) -> f32 {
533 self.linear_velocity.length_squared()
534 }
535
536 #[inline]
538 pub fn kinetic_energy(&self) -> f32 {
539 0.5 * self.mass * self.linear_speed_squared()
540 }
541
542 pub fn set_velocity(&mut self, velocity: Vec2) {
548 self.linear_velocity = velocity;
549 self.wake();
550 }
551
552 pub fn set_angular_velocity(&mut self, angular_velocity: f32) {
554 self.angular_velocity = angular_velocity;
555 self.wake();
556 }
557
558 pub fn set_mass(&mut self, mass: f32) {
564 assert!(self.is_dynamic(), "Cannot set mass on non-dynamic body");
565 assert!(
566 mass > 0.0 && mass.is_finite(),
567 "Mass must be positive and finite"
568 );
569 self.mass = mass;
570 self.inverse_mass = 1.0 / mass;
571 }
572
573 pub fn set_body_type(&mut self, body_type: RigidBodyType) {
575 if self.body_type == body_type {
576 return;
577 }
578
579 self.body_type = body_type;
580
581 if body_type == RigidBodyType::Dynamic {
583 if self.mass == 0.0 {
584 self.mass = 1.0;
585 }
586 self.inverse_mass = 1.0 / self.mass;
587 if self.inertia == 0.0 {
588 self.inertia = 1.0;
589 }
590 self.inverse_inertia = 1.0 / self.inertia;
591 } else {
592 self.inverse_mass = 0.0;
593 self.inverse_inertia = 0.0;
594 }
595
596 self.wake();
597 }
598
599 pub fn apply_force(&mut self, _force: Vec2) {
618 if !self.is_dynamic() {
619 return;
620 }
621 self.wake();
625 }
626
627 pub fn apply_impulse(&mut self, impulse: Vec2) {
636 if !self.is_dynamic() {
637 return;
638 }
639 self.linear_velocity = self.linear_velocity + impulse * self.inverse_mass;
640 self.wake();
641 }
642
643 pub fn apply_angular_impulse(&mut self, impulse: f32) {
649 if !self.is_dynamic() || self.has_fixed_rotation() {
650 return;
651 }
652 self.angular_velocity += impulse * self.inverse_inertia;
653 self.wake();
654 }
655
656 pub fn apply_damping(&mut self, dt: f32) {
662 let linear_factor = 1.0 - self.linear_damping * dt;
664 let angular_factor = 1.0 - self.angular_damping * dt;
665
666 self.linear_velocity = self.linear_velocity * linear_factor.max(0.0);
667 self.angular_velocity *= angular_factor.max(0.0);
668 }
669
670 pub fn sleep(&mut self) {
678 self.flags |= RigidBodyFlags::SLEEPING;
679 self.linear_velocity = Vec2::zero();
680 self.angular_velocity = 0.0;
681 self.sleep_time = 0.0;
682 }
683
684 pub fn wake(&mut self) {
686 self.flags &= !RigidBodyFlags::SLEEPING;
687 self.sleep_time = 0.0;
688 }
689
690 pub fn update_sleep_time(
702 &mut self,
703 dt: f32,
704 linear_threshold: f32,
705 angular_threshold: f32,
706 ) -> bool {
707 if !self.can_sleep() || !self.is_dynamic() {
708 self.sleep_time = 0.0;
709 return false;
710 }
711
712 let below_threshold = self.linear_speed_squared() < linear_threshold * linear_threshold
714 && self.angular_velocity.abs() < angular_threshold;
715
716 if below_threshold {
717 self.sleep_time += dt;
718 true
719 } else {
720 self.sleep_time = 0.0;
721 false
722 }
723 }
724}
725
726impl Component for RigidBody {}
728
729impl std::fmt::Display for RigidBody {
734 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
735 write!(
736 f,
737 "RigidBody({}, vel: {:?}, mass: {}, sleeping: {})",
738 self.body_type,
739 self.linear_velocity,
740 self.mass,
741 self.is_sleeping()
742 )
743 }
744}
745
746#[cfg(test)]
751mod tests {
752 use super::*;
753
754 #[test]
759 fn test_rigidbody_type_default() {
760 assert_eq!(RigidBodyType::default(), RigidBodyType::Dynamic);
761 }
762
763 #[test]
764 fn test_rigidbody_type_is_affected_by_gravity() {
765 assert!(RigidBodyType::Dynamic.is_affected_by_gravity());
766 assert!(!RigidBodyType::Kinematic.is_affected_by_gravity());
767 assert!(!RigidBodyType::Static.is_affected_by_gravity());
768 }
769
770 #[test]
771 fn test_rigidbody_type_is_affected_by_forces() {
772 assert!(RigidBodyType::Dynamic.is_affected_by_forces());
773 assert!(!RigidBodyType::Kinematic.is_affected_by_forces());
774 assert!(!RigidBodyType::Static.is_affected_by_forces());
775 }
776
777 #[test]
778 fn test_rigidbody_type_can_move() {
779 assert!(RigidBodyType::Dynamic.can_move());
780 assert!(RigidBodyType::Kinematic.can_move());
781 assert!(!RigidBodyType::Static.can_move());
782 }
783
784 #[test]
785 fn test_rigidbody_type_responds_to_collisions() {
786 assert!(RigidBodyType::Dynamic.responds_to_collisions());
787 assert!(!RigidBodyType::Kinematic.responds_to_collisions());
788 assert!(!RigidBodyType::Static.responds_to_collisions());
789 }
790
791 #[test]
792 fn test_rigidbody_type_name() {
793 assert_eq!(RigidBodyType::Dynamic.name(), "Dynamic");
794 assert_eq!(RigidBodyType::Kinematic.name(), "Kinematic");
795 assert_eq!(RigidBodyType::Static.name(), "Static");
796 }
797
798 #[test]
799 fn test_rigidbody_type_display() {
800 assert_eq!(format!("{}", RigidBodyType::Dynamic), "Dynamic");
801 assert_eq!(format!("{}", RigidBodyType::Kinematic), "Kinematic");
802 assert_eq!(format!("{}", RigidBodyType::Static), "Static");
803 }
804
805 #[test]
810 fn test_rigidbody_new_dynamic() {
811 let body = RigidBody::new(RigidBodyType::Dynamic);
812 assert_eq!(body.body_type, RigidBodyType::Dynamic);
813 assert_eq!(body.mass, 1.0);
814 assert_eq!(body.inverse_mass, 1.0);
815 assert!(body.can_sleep());
816 assert!(!body.is_sleeping());
817 }
818
819 #[test]
820 fn test_rigidbody_new_kinematic() {
821 let body = RigidBody::new(RigidBodyType::Kinematic);
822 assert_eq!(body.body_type, RigidBodyType::Kinematic);
823 assert_eq!(body.mass, 0.0);
824 assert_eq!(body.inverse_mass, 0.0);
825 }
826
827 #[test]
828 fn test_rigidbody_new_static() {
829 let body = RigidBody::new(RigidBodyType::Static);
830 assert_eq!(body.body_type, RigidBodyType::Static);
831 assert_eq!(body.mass, 0.0);
832 assert_eq!(body.inverse_mass, 0.0);
833 }
834
835 #[test]
836 fn test_rigidbody_dynamic() {
837 let body = RigidBody::dynamic();
838 assert!(body.is_dynamic());
839 assert!(!body.is_kinematic());
840 assert!(!body.is_static());
841 }
842
843 #[test]
844 fn test_rigidbody_kinematic() {
845 let body = RigidBody::kinematic();
846 assert!(!body.is_dynamic());
847 assert!(body.is_kinematic());
848 assert!(!body.is_static());
849 }
850
851 #[test]
852 fn test_rigidbody_static_body() {
853 let body = RigidBody::static_body();
854 assert!(!body.is_dynamic());
855 assert!(!body.is_kinematic());
856 assert!(body.is_static());
857 }
858
859 #[test]
860 fn test_rigidbody_default() {
861 let body = RigidBody::default();
862 assert!(body.is_dynamic());
863 assert_eq!(body.mass, 1.0);
864 }
865
866 #[test]
871 fn test_rigidbody_with_velocity() {
872 let body = RigidBody::dynamic().with_velocity(Vec2::new(100.0, 50.0));
873 assert_eq!(body.linear_velocity, Vec2::new(100.0, 50.0));
874 }
875
876 #[test]
877 fn test_rigidbody_with_angular_velocity() {
878 let body = RigidBody::dynamic().with_angular_velocity(3.14);
879 assert_eq!(body.angular_velocity, 3.14);
880 }
881
882 #[test]
883 fn test_rigidbody_with_mass() {
884 let body = RigidBody::dynamic().with_mass(2.0);
885 assert_eq!(body.mass, 2.0);
886 assert_eq!(body.inverse_mass, 0.5);
887 }
888
889 #[test]
890 #[should_panic(expected = "Mass must be positive and finite")]
891 fn test_rigidbody_with_mass_zero() {
892 let _ = RigidBody::dynamic().with_mass(0.0);
893 }
894
895 #[test]
896 #[should_panic(expected = "Mass must be positive and finite")]
897 fn test_rigidbody_with_mass_negative() {
898 let _ = RigidBody::dynamic().with_mass(-1.0);
899 }
900
901 #[test]
902 fn test_rigidbody_with_damping() {
903 let body = RigidBody::dynamic()
904 .with_linear_damping(0.5)
905 .with_angular_damping(0.3);
906 assert_eq!(body.linear_damping, 0.5);
907 assert_eq!(body.angular_damping, 0.3);
908 }
909
910 #[test]
911 fn test_rigidbody_with_restitution() {
912 let body = RigidBody::dynamic().with_restitution(0.8);
913 assert_eq!(body.restitution, 0.8);
914 }
915
916 #[test]
917 fn test_rigidbody_with_friction() {
918 let body = RigidBody::dynamic().with_friction(0.7);
919 assert_eq!(body.friction, 0.7);
920 }
921
922 #[test]
923 fn test_rigidbody_with_gravity_scale() {
924 let body = RigidBody::dynamic().with_gravity_scale(2.0);
925 assert_eq!(body.gravity_scale, 2.0);
926 }
927
928 #[test]
929 fn test_rigidbody_with_can_sleep() {
930 let body1 = RigidBody::dynamic().with_can_sleep(true);
931 assert!(body1.can_sleep());
932
933 let body2 = RigidBody::dynamic().with_can_sleep(false);
934 assert!(!body2.can_sleep());
935 }
936
937 #[test]
938 fn test_rigidbody_with_continuous_cd() {
939 let body1 = RigidBody::dynamic().with_continuous_cd(true);
940 assert!(body1.has_continuous_cd());
941
942 let body2 = RigidBody::dynamic().with_continuous_cd(false);
943 assert!(!body2.has_continuous_cd());
944 }
945
946 #[test]
947 fn test_rigidbody_with_fixed_rotation() {
948 let body = RigidBody::dynamic()
949 .with_angular_velocity(5.0)
950 .with_fixed_rotation(true);
951
952 assert!(body.has_fixed_rotation());
953 assert_eq!(body.angular_velocity, 0.0);
954 assert_eq!(body.inertia, 0.0);
955 assert_eq!(body.inverse_inertia, 0.0);
956 }
957
958 #[test]
959 fn test_rigidbody_builder_chaining() {
960 let body = RigidBody::dynamic()
961 .with_velocity(Vec2::new(100.0, 50.0))
962 .with_mass(2.0)
963 .with_restitution(0.8)
964 .with_friction(0.5)
965 .with_gravity_scale(1.5);
966
967 assert_eq!(body.linear_velocity, Vec2::new(100.0, 50.0));
968 assert_eq!(body.mass, 2.0);
969 assert_eq!(body.restitution, 0.8);
970 assert_eq!(body.friction, 0.5);
971 assert_eq!(body.gravity_scale, 1.5);
972 }
973
974 #[test]
979 fn test_rigidbody_linear_speed() {
980 let body = RigidBody::dynamic().with_velocity(Vec2::new(3.0, 4.0));
981 assert_eq!(body.linear_speed(), 5.0);
982 }
983
984 #[test]
985 fn test_rigidbody_linear_speed_squared() {
986 let body = RigidBody::dynamic().with_velocity(Vec2::new(3.0, 4.0));
987 assert_eq!(body.linear_speed_squared(), 25.0);
988 }
989
990 #[test]
991 fn test_rigidbody_kinetic_energy() {
992 let body = RigidBody::dynamic()
993 .with_mass(2.0)
994 .with_velocity(Vec2::new(3.0, 4.0));
995 assert_eq!(body.kinetic_energy(), 25.0);
997 }
998
999 #[test]
1004 fn test_rigidbody_set_velocity() {
1005 let mut body = RigidBody::dynamic();
1006 body.set_velocity(Vec2::new(100.0, 50.0));
1007 assert_eq!(body.linear_velocity, Vec2::new(100.0, 50.0));
1008 assert!(!body.is_sleeping()); }
1010
1011 #[test]
1012 fn test_rigidbody_set_angular_velocity() {
1013 let mut body = RigidBody::dynamic();
1014 body.set_angular_velocity(3.14);
1015 assert_eq!(body.angular_velocity, 3.14);
1016 assert!(!body.is_sleeping()); }
1018
1019 #[test]
1020 fn test_rigidbody_set_mass() {
1021 let mut body = RigidBody::dynamic();
1022 body.set_mass(2.0);
1023 assert_eq!(body.mass, 2.0);
1024 assert_eq!(body.inverse_mass, 0.5);
1025 }
1026
1027 #[test]
1028 #[should_panic(expected = "Cannot set mass on non-dynamic body")]
1029 fn test_rigidbody_set_mass_kinematic() {
1030 let mut body = RigidBody::kinematic();
1031 body.set_mass(2.0);
1032 }
1033
1034 #[test]
1035 fn test_rigidbody_set_body_type() {
1036 let mut body = RigidBody::dynamic();
1037 body.set_body_type(RigidBodyType::Kinematic);
1038
1039 assert!(body.is_kinematic());
1040 assert_eq!(body.inverse_mass, 0.0);
1041 assert_eq!(body.inverse_inertia, 0.0);
1042 }
1043
1044 #[test]
1049 fn test_rigidbody_apply_impulse() {
1050 let mut body = RigidBody::dynamic().with_mass(2.0);
1051
1052 body.apply_impulse(Vec2::new(10.0, 0.0));
1053 assert_eq!(body.linear_velocity, Vec2::new(5.0, 0.0));
1055 }
1056
1057 #[test]
1058 fn test_rigidbody_apply_impulse_kinematic() {
1059 let mut body = RigidBody::kinematic();
1060 let initial_velocity = body.linear_velocity;
1061
1062 body.apply_impulse(Vec2::new(10.0, 0.0));
1063 assert_eq!(body.linear_velocity, initial_velocity);
1065 }
1066
1067 #[test]
1068 fn test_rigidbody_apply_angular_impulse() {
1069 let mut body = RigidBody::dynamic();
1070 body.apply_angular_impulse(5.0);
1071 assert_eq!(body.angular_velocity, 5.0);
1073 }
1074
1075 #[test]
1076 fn test_rigidbody_apply_angular_impulse_fixed_rotation() {
1077 let mut body = RigidBody::dynamic().with_fixed_rotation(true);
1078
1079 body.apply_angular_impulse(5.0);
1080 assert_eq!(body.angular_velocity, 0.0);
1082 }
1083
1084 #[test]
1085 fn test_rigidbody_apply_damping() {
1086 let mut body = RigidBody::dynamic()
1087 .with_velocity(Vec2::new(100.0, 0.0))
1088 .with_angular_velocity(10.0)
1089 .with_linear_damping(0.1)
1090 .with_angular_damping(0.1);
1091
1092 body.apply_damping(0.1); assert!(body.linear_velocity.x < 100.0);
1096 assert!(body.angular_velocity < 10.0);
1097 }
1098
1099 #[test]
1104 fn test_rigidbody_sleep() {
1105 let mut body = RigidBody::dynamic()
1106 .with_velocity(Vec2::new(100.0, 50.0))
1107 .with_angular_velocity(5.0);
1108
1109 body.sleep();
1110
1111 assert!(body.is_sleeping());
1112 assert_eq!(body.linear_velocity, Vec2::zero());
1113 assert_eq!(body.angular_velocity, 0.0);
1114 assert_eq!(body.sleep_time, 0.0);
1115 }
1116
1117 #[test]
1118 fn test_rigidbody_wake() {
1119 let mut body = RigidBody::dynamic();
1120 body.sleep();
1121 assert!(body.is_sleeping());
1122
1123 body.wake();
1124 assert!(!body.is_sleeping());
1125 assert_eq!(body.sleep_time, 0.0);
1126 }
1127
1128 #[test]
1129 fn test_rigidbody_update_sleep_time_below_threshold() {
1130 let mut body = RigidBody::dynamic().with_velocity(Vec2::new(1.0, 1.0));
1131
1132 let should_sleep = body.update_sleep_time(0.1, 5.0, 0.1);
1133 assert!(should_sleep);
1134 assert!(body.sleep_time > 0.0);
1135 }
1136
1137 #[test]
1138 fn test_rigidbody_update_sleep_time_above_threshold() {
1139 let mut body = RigidBody::dynamic().with_velocity(Vec2::new(100.0, 0.0));
1140
1141 let should_sleep = body.update_sleep_time(0.1, 5.0, 0.1);
1142 assert!(!should_sleep);
1143 assert_eq!(body.sleep_time, 0.0);
1144 }
1145
1146 #[test]
1147 fn test_rigidbody_update_sleep_time_cannot_sleep() {
1148 let mut body = RigidBody::dynamic()
1149 .with_can_sleep(false)
1150 .with_velocity(Vec2::new(1.0, 1.0));
1151
1152 let should_sleep = body.update_sleep_time(0.1, 5.0, 0.1);
1153 assert!(!should_sleep);
1154 assert_eq!(body.sleep_time, 0.0);
1155 }
1156
1157 #[test]
1162 fn test_rigidbody_is_component() {
1163 fn requires_component<T: Component>() {}
1164 requires_component::<RigidBody>();
1165 }
1166
1167 #[test]
1168 fn test_rigidbody_display() {
1169 let body = RigidBody::dynamic().with_velocity(Vec2::new(100.0, 50.0));
1170
1171 let display = format!("{}", body);
1172 assert!(display.contains("RigidBody"));
1173 assert!(display.contains("Dynamic"));
1174 assert!(display.contains("vel"));
1175 assert!(display.contains("mass"));
1176 }
1177
1178 #[test]
1179 fn test_rigidbody_debug() {
1180 let body = RigidBody::dynamic();
1181 let debug = format!("{:?}", body);
1182 assert!(debug.contains("RigidBody"));
1183 }
1184
1185 #[test]
1186 fn test_rigidbody_clone() {
1187 let body1 = RigidBody::dynamic()
1188 .with_velocity(Vec2::new(100.0, 50.0))
1189 .with_mass(2.0);
1190
1191 let body2 = body1;
1192 assert_eq!(body1.linear_velocity, body2.linear_velocity);
1193 assert_eq!(body1.mass, body2.mass);
1194 }
1195
1196 #[test]
1201 fn test_rigidbody_is_send() {
1202 fn requires_send<T: Send>() {}
1203 requires_send::<RigidBody>();
1204 }
1205
1206 #[test]
1207 fn test_rigidbody_is_sync() {
1208 fn requires_sync<T: Sync>() {}
1209 requires_sync::<RigidBody>();
1210 }
1211}