arcane_engine/physics/
sleep.rs1use super::types::{BodyType, Contact, RigidBody};
2
3const SLEEP_VELOCITY_THRESHOLD: f32 = 8.0;
7const SLEEP_ANGULAR_THRESHOLD: f32 = 0.5;
8const SLEEP_TIME_THRESHOLD: f32 = 0.3;
9
10pub fn update_sleep(
14 bodies: &mut [Option<RigidBody>],
15 contacts: &[Contact],
16 dt: f32,
17) {
18 let len = bodies.len();
19 if len == 0 {
20 return;
21 }
22
23 let mut parent: Vec<usize> = (0..len).collect();
26
27 fn find(parent: &mut [usize], mut x: usize) -> usize {
29 while parent[x] != x {
30 parent[x] = parent[parent[x]]; x = parent[x];
32 }
33 x
34 }
35 fn union(parent: &mut [usize], a: usize, b: usize) {
36 let ra = find(parent, a);
37 let rb = find(parent, b);
38 if ra != rb {
39 parent[rb] = ra;
40 }
41 }
42
43 for contact in contacts {
45 let a = contact.body_a as usize;
46 let b = contact.body_b as usize;
47 if a >= len || b >= len {
48 continue;
49 }
50 let a_dynamic = bodies[a]
51 .as_ref()
52 .map_or(false, |b| b.body_type == BodyType::Dynamic);
53 let b_dynamic = bodies[b]
54 .as_ref()
55 .map_or(false, |b| b.body_type == BodyType::Dynamic);
56
57 if a_dynamic && b_dynamic {
58 union(&mut parent, a, b);
59 }
60 }
61
62 let mut island_map: std::collections::HashMap<usize, Vec<usize>> =
64 std::collections::HashMap::new();
65 for i in 0..len {
66 let is_dynamic = bodies[i]
67 .as_ref()
68 .map_or(false, |b| b.body_type == BodyType::Dynamic);
69 if !is_dynamic {
70 continue;
71 }
72 let root = find(&mut parent, i);
73 island_map.entry(root).or_default().push(i);
74 }
75
76 let threshold_sq = SLEEP_VELOCITY_THRESHOLD * SLEEP_VELOCITY_THRESHOLD;
77
78 for (_root, members) in &island_map {
80 let all_below = members.iter().all(|&i| {
82 let b = bodies[i].as_ref().unwrap();
83 let speed_sq = b.vx * b.vx + b.vy * b.vy;
84 speed_sq < threshold_sq && b.angular_velocity.abs() < SLEEP_ANGULAR_THRESHOLD
85 });
86
87 if all_below {
88 let mut min_timer = f32::MAX;
90 for &i in members {
91 let b = bodies[i].as_mut().unwrap();
92 b.sleep_timer += dt;
93 min_timer = min_timer.min(b.sleep_timer);
94 }
95
96 if min_timer > SLEEP_TIME_THRESHOLD {
98 for &i in members {
99 let b = bodies[i].as_mut().unwrap();
100 b.sleeping = true;
101 b.vx = 0.0;
102 b.vy = 0.0;
103 b.angular_velocity = 0.0;
104 }
105 }
106 } else {
107 for &i in members {
109 let b = bodies[i].as_mut().unwrap();
110 b.sleep_timer = 0.0;
111 b.sleeping = false;
112 }
113 }
114 }
115}