rapier2d/dynamics/island_manager/sleep.rs
1use crate::dynamics::{
2 ImpulseJointSet, MultibodyJointSet, RigidBodyHandle, RigidBodySet, SleepRootState,
3};
4use crate::geometry::{ColliderSet, NarrowPhase};
5
6use super::{Island, IslandManager};
7
8impl IslandManager {
9 /// Wakes up a sleeping body, forcing it back into the active simulation.
10 ///
11 /// Use this when you want to ensure a body is active (useful after manually moving
12 /// a sleeping body, or to prevent it from sleeping in the next few frames).
13 ///
14 /// # Parameters
15 /// * `strong` - If `true`, the body is guaranteed to stay awake for multiple frames.
16 /// If `false`, it might sleep again immediately if conditions are met.
17 ///
18 /// # Example
19 /// ```
20 /// # use rapier3d::prelude::*;
21 /// # let mut bodies = RigidBodySet::new();
22 /// # let mut islands = IslandManager::new();
23 /// # let body_handle = bodies.insert(RigidBodyBuilder::dynamic());
24 /// islands.wake_up(&mut bodies, body_handle, true);
25 /// let body = bodies.get_mut(body_handle).unwrap();
26 /// // Wake up a body before applying force to it
27 /// body.add_force(Vector::new(100.0, 0.0, 0.0), false);
28 /// ```
29 ///
30 /// Only affects dynamic bodies (kinematic and fixed bodies don't sleep).
31 pub fn wake_up(&mut self, bodies: &mut RigidBodySet, handle: RigidBodyHandle, strong: bool) {
32 // NOTE: the use an Option here because there are many legitimate cases (like when
33 // deleting a joint attached to an already-removed body) where we could be
34 // attempting to wake-up a rigid-body that has already been deleted.
35 if bodies.get(handle).map(|rb| !rb.is_fixed()) == Some(true) {
36 let rb = bodies.index_mut_internal(handle);
37
38 // TODO: not sure if this is still relevant:
39 // // Check that the user didn’t change the sleeping state explicitly, in which
40 // // case we don’t overwrite it.
41 // if rb.changes.contains(RigidBodyChanges::SLEEP) {
42 // return;
43 // }
44
45 rb.activation.wake_up(strong);
46 let island_to_wake_up = rb.ids.active_island_id;
47 self.wake_up_island(bodies, island_to_wake_up);
48 }
49 }
50
51 /// Returns the number of iterations run by the graph traversal so we can balance load across
52 /// frames.
53 pub(super) fn extract_sleeping_island(
54 &mut self,
55 bodies: &mut RigidBodySet,
56 colliders: &ColliderSet,
57 impulse_joints: &ImpulseJointSet,
58 multibody_joints: &MultibodyJointSet,
59 narrow_phase: &NarrowPhase,
60 sleep_root: RigidBodyHandle,
61 ) -> usize {
62 let Some(rb) = bodies.get_mut_internal(sleep_root) else {
63 // This branch happens if the rigid-body no longer exists.
64 return 0;
65 };
66
67 if rb.activation.sleep_root_state != SleepRootState::TraversalPending {
68 // We already traversed this sleep root.
69 return 0;
70 }
71
72 rb.activation.sleep_root_state = SleepRootState::Traversed;
73
74 let active_island_id = rb.ids.active_island_id;
75 let active_island = &mut self.islands[active_island_id];
76 if active_island.is_sleeping() {
77 // This rigid-body is already part of a sleeping island.
78 return 0;
79 }
80
81 // TODO: implement recycling islands to avoid repeated allocations?
82 let mut new_island = Island::default();
83 self.stack.clear();
84 self.stack.push(sleep_root);
85
86 let mut niter = 0;
87 self.traversal_timestamp += 1;
88
89 while let Some(handle) = self.stack.pop() {
90 let rb = bodies.index_mut_internal(handle);
91
92 if rb.is_fixed() {
93 // Don’t propagate islands through fixed bodies.
94 continue;
95 }
96
97 if rb.ids.active_set_timestamp == self.traversal_timestamp {
98 // We already visited this body and its neighbors.
99 continue;
100 }
101
102 // if rb.ids.active_set_timestamp >= frame_base_timestamp {
103 // // We already visited this body and its neighbors during this frame.
104 // // So we already know this islands cannot sleep (otherwise the bodies
105 // // currently being traversed would already have been marked as sleeping).
106 // return niter;
107 // }
108
109 niter += 1;
110 rb.ids.active_set_timestamp = self.traversal_timestamp;
111
112 if rb.activation.is_eligible_for_sleep() {
113 rb.activation.sleep_root_state = SleepRootState::Traversed;
114 }
115
116 assert_eq!(
117 rb.ids.active_island_id,
118 active_island_id,
119 "handle: {:?}, note niter: {}, isl size: {}",
120 handle,
121 niter,
122 active_island.len()
123 );
124 assert!(
125 !rb.activation.sleeping,
126 "is sleeping: {:?} note niter: {}, isl size: {}",
127 handle,
128 niter,
129 active_island.len()
130 );
131
132 if !rb.activation.is_eligible_for_sleep() {
133 // If this body cannot sleep, abort the traversal, we are not traversing
134 // yet an island that can sleep.
135 self.stack.clear();
136 return niter;
137 }
138
139 // Traverse bodies that are interacting with the current one either through
140 // contacts or a joint.
141 super::utils::push_contacting_bodies(
142 &rb.colliders,
143 colliders,
144 narrow_phase,
145 &mut self.stack,
146 );
147 super::utils::push_linked_bodies(
148 impulse_joints,
149 multibody_joints,
150 handle,
151 &mut self.stack,
152 );
153 new_island.bodies.push(handle);
154 }
155
156 // If we reached this line, we completed a sleeping island traversal.
157 // - Put its bodies to sleep.
158 // - Remove them from the active set.
159 // - Push the sleeping island.
160 if active_island.len() == new_island.len() {
161 // The whole island is asleep. No need to insert a new one.
162 // Put all its bodies to sleep.
163 for handle in &active_island.bodies {
164 let rb = bodies.index_mut_internal(*handle);
165 rb.sleep();
166 }
167
168 // Mark the existing island as sleeping (by clearing its `id_in_awake_list`)
169 // and remove it from the awake list.
170 let island_awake_id = active_island
171 .id_in_awake_list
172 .take()
173 .unwrap_or_else(|| unreachable!());
174 self.awake_islands.swap_remove(island_awake_id);
175
176 if let Some(moved_id) = self.awake_islands.get(island_awake_id) {
177 self.islands[*moved_id].id_in_awake_list = Some(island_awake_id);
178 }
179 } else {
180 niter += new_island.len(); // Include this part into the cost estimate for this function.
181 self.extract_sub_island(bodies, active_island_id, new_island, true);
182 }
183 niter
184 }
185
186 fn wake_up_island(&mut self, bodies: &mut RigidBodySet, island_id: usize) {
187 let Some(island) = self.islands.get_mut(island_id) else {
188 return;
189 };
190
191 if island.is_sleeping() {
192 island.id_in_awake_list = Some(self.awake_islands.len());
193 self.awake_islands.push(island_id);
194
195 // Wake up all the bodies from this island.
196 for handle in &island.bodies {
197 if let Some(rb) = bodies.get_mut(*handle) {
198 rb.wake_up(false);
199 }
200 }
201 }
202 }
203}