Skip to main content

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}