rapier2d/dynamics/rigid_body_set.rs
1use crate::data::{Arena, HasModifiedFlag, ModifiedObjects};
2use crate::dynamics::{
3 ImpulseJointSet, IslandManager, MultibodyJointSet, RigidBody, RigidBodyBuilder,
4 RigidBodyChanges, RigidBodyHandle,
5};
6use crate::geometry::ColliderSet;
7use std::ops::{Index, IndexMut};
8
9#[cfg(doc)]
10use crate::pipeline::PhysicsPipeline;
11
12#[derive(Copy, Clone, Debug, PartialEq, Eq)]
13#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
14/// A pair of rigid body handles.
15pub struct BodyPair {
16 /// The first rigid body handle.
17 pub body1: RigidBodyHandle,
18 /// The second rigid body handle.
19 pub body2: RigidBodyHandle,
20}
21
22impl BodyPair {
23 /// Builds a new pair of rigid-body handles.
24 pub fn new(body1: RigidBodyHandle, body2: RigidBodyHandle) -> Self {
25 BodyPair { body1, body2 }
26 }
27}
28
29pub(crate) type ModifiedRigidBodies = ModifiedObjects<RigidBodyHandle, RigidBody>;
30
31impl HasModifiedFlag for RigidBody {
32 #[inline]
33 fn has_modified_flag(&self) -> bool {
34 self.changes.contains(RigidBodyChanges::MODIFIED)
35 }
36
37 #[inline]
38 fn set_modified_flag(&mut self) {
39 self.changes |= RigidBodyChanges::MODIFIED;
40 }
41}
42
43#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
44#[derive(Clone, Default, Debug)]
45/// The collection that stores all rigid bodies in your physics world.
46///
47/// This is where you add, remove, and access all your physics objects. Think of it as
48/// a "database" of all rigid bodies, where each body gets a unique handle for fast lookup.
49///
50/// # Why use handles?
51///
52/// Instead of storing bodies directly, you get back a [`RigidBodyHandle`] when inserting.
53/// This handle is lightweight (just an index + generation) and remains valid even if other
54/// bodies are removed, protecting you from use-after-free bugs.
55///
56/// # Example
57///
58/// ```
59/// # use rapier3d::prelude::*;
60/// let mut bodies = RigidBodySet::new();
61///
62/// // Add a dynamic body
63/// let handle = bodies.insert(RigidBodyBuilder::dynamic());
64///
65/// // Access it later
66/// if let Some(body) = bodies.get_mut(handle) {
67/// body.apply_impulse(vector![0.0, 10.0, 0.0], true);
68/// }
69/// ```
70pub struct RigidBodySet {
71 // NOTE: the pub(crate) are needed by the broad phase
72 // to avoid borrowing issues. It is also needed for
73 // parallelism because the `Receiver` breaks the Sync impl.
74 // Could we avoid this?
75 pub(crate) bodies: Arena<RigidBody>,
76 pub(crate) modified_bodies: ModifiedRigidBodies,
77 #[cfg_attr(feature = "serde-serialize", serde(skip))]
78 pub(crate) default_fixed: RigidBody,
79}
80
81impl RigidBodySet {
82 /// Creates a new empty collection of rigid bodies.
83 ///
84 /// Call this once when setting up your physics world. The collection will
85 /// automatically grow as you add more bodies.
86 pub fn new() -> Self {
87 RigidBodySet {
88 bodies: Arena::new(),
89 modified_bodies: ModifiedObjects::default(),
90 default_fixed: RigidBodyBuilder::fixed().build(),
91 }
92 }
93
94 /// Creates a new collection with pre-allocated space for the given number of bodies.
95 ///
96 /// Use this if you know approximately how many bodies you'll need, to avoid
97 /// multiple reallocations as the collection grows.
98 ///
99 /// # Example
100 /// ```
101 /// # use rapier3d::prelude::*;
102 /// // You know you'll have ~1000 bodies
103 /// let mut bodies = RigidBodySet::with_capacity(1000);
104 /// ```
105 pub fn with_capacity(capacity: usize) -> Self {
106 RigidBodySet {
107 bodies: Arena::with_capacity(capacity),
108 modified_bodies: ModifiedRigidBodies::with_capacity(capacity),
109 default_fixed: RigidBodyBuilder::fixed().build(),
110 }
111 }
112
113 pub(crate) fn take_modified(&mut self) -> ModifiedRigidBodies {
114 std::mem::take(&mut self.modified_bodies)
115 }
116
117 /// Returns how many rigid bodies are currently in this collection.
118 pub fn len(&self) -> usize {
119 self.bodies.len()
120 }
121
122 /// Returns `true` if there are no rigid bodies in this collection.
123 pub fn is_empty(&self) -> bool {
124 self.bodies.is_empty()
125 }
126
127 /// Checks if the given handle points to a valid rigid body that still exists.
128 ///
129 /// Returns `false` if the body was removed or the handle is invalid.
130 pub fn contains(&self, handle: RigidBodyHandle) -> bool {
131 self.bodies.contains(handle.0)
132 }
133
134 /// Adds a rigid body to the world and returns its handle for future access.
135 ///
136 /// The handle is how you'll refer to this body later (to move it, apply forces, etc.).
137 /// Keep the handle somewhere accessible - you can't get the body back without it!
138 ///
139 /// # Example
140 /// ```
141 /// # use rapier3d::prelude::*;
142 /// # let mut bodies = RigidBodySet::new();
143 /// let handle = bodies.insert(
144 /// RigidBodyBuilder::dynamic()
145 /// .translation(vector![0.0, 5.0, 0.0])
146 /// .build()
147 /// );
148 /// // Store `handle` to access this body later
149 /// ```
150 pub fn insert(&mut self, rb: impl Into<RigidBody>) -> RigidBodyHandle {
151 let mut rb = rb.into();
152 // Make sure the internal links are reset, they may not be
153 // if this rigid-body was obtained by cloning another one.
154 rb.reset_internal_references();
155 rb.changes.set(RigidBodyChanges::all(), true);
156
157 let handle = RigidBodyHandle(self.bodies.insert(rb));
158 // Using push_unchecked because this is a brand new rigid-body with the MODIFIED
159 // flags set but isn’t in the modified_bodies yet.
160 self.modified_bodies
161 .push_unchecked(handle, &mut self.bodies[handle.0]);
162 handle
163 }
164
165 /// Removes a rigid body from the world along with all its attached colliders and joints.
166 ///
167 /// This is a complete cleanup operation that removes:
168 /// - The rigid body itself
169 /// - All colliders attached to it (if `remove_attached_colliders` is `true`)
170 /// - All joints connected to this body
171 ///
172 /// Returns the removed body if it existed, or `None` if the handle was invalid.
173 ///
174 /// # Parameters
175 ///
176 /// * `remove_attached_colliders` - If `true`, removes all colliders attached to this body.
177 /// If `false`, the colliders are detached and become independent.
178 ///
179 /// # Example
180 /// ```
181 /// # use rapier3d::prelude::*;
182 /// # let mut bodies = RigidBodySet::new();
183 /// # let mut islands = IslandManager::new();
184 /// # let mut colliders = ColliderSet::new();
185 /// # let mut impulse_joints = ImpulseJointSet::new();
186 /// # let mut multibody_joints = MultibodyJointSet::new();
187 /// # let handle = bodies.insert(RigidBodyBuilder::dynamic());
188 /// // Remove a body and everything attached to it
189 /// if let Some(body) = bodies.remove(
190 /// handle,
191 /// &mut islands,
192 /// &mut colliders,
193 /// &mut impulse_joints,
194 /// &mut multibody_joints,
195 /// true // Remove colliders too
196 /// ) {
197 /// println!("Removed body at {:?}", body.translation());
198 /// }
199 /// ```
200 #[profiling::function]
201 pub fn remove(
202 &mut self,
203 handle: RigidBodyHandle,
204 islands: &mut IslandManager,
205 colliders: &mut ColliderSet,
206 impulse_joints: &mut ImpulseJointSet,
207 multibody_joints: &mut MultibodyJointSet,
208 remove_attached_colliders: bool,
209 ) -> Option<RigidBody> {
210 let rb = self.bodies.remove(handle.0)?;
211 /*
212 * Update active sets.
213 */
214 islands.rigid_body_removed(handle, &rb.ids, self);
215
216 /*
217 * Remove colliders attached to this rigid-body.
218 */
219 if remove_attached_colliders {
220 for collider in rb.colliders() {
221 colliders.remove(*collider, islands, self, false);
222 }
223 } else {
224 // If we don’t remove the attached colliders, simply detach them.
225 let colliders_to_detach = rb.colliders().to_vec();
226 for co_handle in colliders_to_detach {
227 colliders.set_parent(co_handle, None, self);
228 }
229 }
230
231 /*
232 * Remove impulse_joints attached to this rigid-body.
233 */
234 impulse_joints.remove_joints_attached_to_rigid_body(handle);
235 multibody_joints.remove_joints_attached_to_rigid_body(handle);
236
237 Some(rb)
238 }
239
240 /// Gets a rigid body by its index without knowing the generation number.
241 ///
242 /// ⚠️ **Advanced/unsafe usage** - prefer [`get()`](Self::get) instead!
243 ///
244 /// This bypasses the generation check that normally protects against the ABA problem
245 /// (where an index gets reused after removal). Only use this if you're certain the
246 /// body at this index is the one you expect.
247 ///
248 /// Returns both the body and its current handle (with the correct generation).
249 pub fn get_unknown_gen(&self, i: u32) -> Option<(&RigidBody, RigidBodyHandle)> {
250 self.bodies
251 .get_unknown_gen(i)
252 .map(|(b, h)| (b, RigidBodyHandle(h)))
253 }
254
255 /// Gets a mutable reference to a rigid body by its index without knowing the generation.
256 ///
257 /// ⚠️ **Advanced/unsafe usage** - prefer [`get_mut()`](Self::get_mut) instead!
258 ///
259 /// This bypasses the generation check. See [`get_unknown_gen()`](Self::get_unknown_gen)
260 /// for more details on when this is appropriate (rarely).
261 #[cfg(not(feature = "dev-remove-slow-accessors"))]
262 pub fn get_unknown_gen_mut(&mut self, i: u32) -> Option<(&mut RigidBody, RigidBodyHandle)> {
263 let (rb, handle) = self.bodies.get_unknown_gen_mut(i)?;
264 let handle = RigidBodyHandle(handle);
265 self.modified_bodies.push_once(handle, rb);
266 Some((rb, handle))
267 }
268
269 /// Gets a read-only reference to the rigid body with the given handle.
270 ///
271 /// Returns `None` if the handle is invalid or the body was removed.
272 ///
273 /// Use this to read body properties like position, velocity, mass, etc.
274 pub fn get(&self, handle: RigidBodyHandle) -> Option<&RigidBody> {
275 self.bodies.get(handle.0)
276 }
277
278 /// Gets a mutable reference to the rigid body with the given handle.
279 ///
280 /// Returns `None` if the handle is invalid or the body was removed.
281 ///
282 /// Use this to modify body properties, apply forces/impulses, change velocities, etc.
283 ///
284 /// # Example
285 /// ```
286 /// # use rapier3d::prelude::*;
287 /// # let mut bodies = RigidBodySet::new();
288 /// # let handle = bodies.insert(RigidBodyBuilder::dynamic());
289 /// if let Some(body) = bodies.get_mut(handle) {
290 /// body.set_linvel(vector![1.0, 0.0, 0.0], true);
291 /// body.apply_impulse(vector![0.0, 100.0, 0.0], true);
292 /// }
293 /// ```
294 #[cfg(not(feature = "dev-remove-slow-accessors"))]
295 pub fn get_mut(&mut self, handle: RigidBodyHandle) -> Option<&mut RigidBody> {
296 let result = self.bodies.get_mut(handle.0)?;
297 self.modified_bodies.push_once(handle, result);
298 Some(result)
299 }
300
301 /// Gets mutable references to two different rigid bodies at once.
302 ///
303 /// This is useful when you need to modify two bodies simultaneously (e.g., when manually
304 /// handling collisions between them). If both handles are the same, only the first value
305 /// will be `Some`.
306 ///
307 /// # Example
308 /// ```
309 /// # use rapier3d::prelude::*;
310 /// # let mut bodies = RigidBodySet::new();
311 /// # let handle1 = bodies.insert(RigidBodyBuilder::dynamic());
312 /// # let handle2 = bodies.insert(RigidBodyBuilder::dynamic());
313 /// let (body1, body2) = bodies.get_pair_mut(handle1, handle2);
314 /// if let (Some(b1), Some(b2)) = (body1, body2) {
315 /// // Can modify both bodies at once
316 /// b1.apply_impulse(vector![10.0, 0.0, 0.0], true);
317 /// b2.apply_impulse(vector![-10.0, 0.0, 0.0], true);
318 /// }
319 /// ```
320 #[cfg(not(feature = "dev-remove-slow-accessors"))]
321 pub fn get_pair_mut(
322 &mut self,
323 handle1: RigidBodyHandle,
324 handle2: RigidBodyHandle,
325 ) -> (Option<&mut RigidBody>, Option<&mut RigidBody>) {
326 if handle1 == handle2 {
327 (self.get_mut(handle1), None)
328 } else {
329 let (mut rb1, mut rb2) = self.bodies.get2_mut(handle1.0, handle2.0);
330 if let Some(rb1) = rb1.as_deref_mut() {
331 self.modified_bodies.push_once(handle1, rb1);
332 }
333 if let Some(rb2) = rb2.as_deref_mut() {
334 self.modified_bodies.push_once(handle2, rb2);
335 }
336 (rb1, rb2)
337 }
338 }
339
340 pub(crate) fn get_mut_internal(&mut self, handle: RigidBodyHandle) -> Option<&mut RigidBody> {
341 self.bodies.get_mut(handle.0)
342 }
343
344 pub(crate) fn index_mut_internal(&mut self, handle: RigidBodyHandle) -> &mut RigidBody {
345 &mut self.bodies[handle.0]
346 }
347
348 // Just a very long name instead of `.get_mut` to make sure
349 // this is really the method we wanted to use instead of `get_mut_internal`.
350 pub(crate) fn get_mut_internal_with_modification_tracking(
351 &mut self,
352 handle: RigidBodyHandle,
353 ) -> Option<&mut RigidBody> {
354 let result = self.bodies.get_mut(handle.0)?;
355 self.modified_bodies.push_once(handle, result);
356 Some(result)
357 }
358
359 /// Iterates over all rigid bodies in this collection.
360 ///
361 /// Each iteration yields a `(handle, &RigidBody)` pair. Use this to read properties
362 /// of all bodies (positions, velocities, etc.) without modifying them.
363 ///
364 /// # Example
365 /// ```
366 /// # use rapier3d::prelude::*;
367 /// # let mut bodies = RigidBodySet::new();
368 /// # bodies.insert(RigidBodyBuilder::dynamic());
369 /// for (handle, body) in bodies.iter() {
370 /// println!("Body {:?} is at {:?}", handle, body.translation());
371 /// }
372 /// ```
373 pub fn iter(&self) -> impl Iterator<Item = (RigidBodyHandle, &RigidBody)> {
374 self.bodies.iter().map(|(h, b)| (RigidBodyHandle(h), b))
375 }
376
377 /// Iterates over all rigid bodies with mutable access.
378 ///
379 /// Each iteration yields a `(handle, &mut RigidBody)` pair. Use this to modify
380 /// multiple bodies in one pass.
381 ///
382 /// # Example
383 /// ```
384 /// # use rapier3d::prelude::*;
385 /// # let mut bodies = RigidBodySet::new();
386 /// # bodies.insert(RigidBodyBuilder::dynamic());
387 /// // Apply gravity manually to all dynamic bodies
388 /// for (handle, body) in bodies.iter_mut() {
389 /// if body.is_dynamic() {
390 /// body.add_force(vector![0.0, -9.81 * body.mass(), 0.0], true);
391 /// }
392 /// }
393 /// ```
394 #[cfg(not(feature = "dev-remove-slow-accessors"))]
395 pub fn iter_mut(&mut self) -> impl Iterator<Item = (RigidBodyHandle, &mut RigidBody)> {
396 self.modified_bodies.clear();
397 let modified_bodies = &mut self.modified_bodies;
398 self.bodies.iter_mut().map(move |(h, b)| {
399 // NOTE: using `push_unchecked` because we just cleared `modified_bodies`
400 // before iterating.
401 modified_bodies.push_unchecked(RigidBodyHandle(h), b);
402 (RigidBodyHandle(h), b)
403 })
404 }
405
406 /// Updates the positions of all colliders attached to bodies that have moved.
407 ///
408 /// Normally you don't need to call this - it's automatically handled by [`PhysicsPipeline::step`].
409 /// Only call this manually if you're:
410 /// - Moving bodies yourself outside of `step()`
411 /// - Using `QueryPipeline` for raycasts without running physics simulation
412 /// - Need collider positions to be immediately up-to-date for some custom logic
413 ///
414 /// This synchronizes collider world positions based on their parent bodies' positions.
415 pub fn propagate_modified_body_positions_to_colliders(&self, colliders: &mut ColliderSet) {
416 for body in self.modified_bodies.iter().filter_map(|h| self.get(*h)) {
417 if body.changes.contains(RigidBodyChanges::POSITION) {
418 for handle in body.colliders() {
419 if let Some(collider) = colliders.get_mut(*handle) {
420 let new_pos = body.position() * collider.position_wrt_parent().unwrap();
421 collider.set_position(new_pos);
422 }
423 }
424 }
425 }
426 }
427}
428
429impl Index<RigidBodyHandle> for RigidBodySet {
430 type Output = RigidBody;
431
432 fn index(&self, index: RigidBodyHandle) -> &RigidBody {
433 &self.bodies[index.0]
434 }
435}
436
437impl Index<crate::data::Index> for RigidBodySet {
438 type Output = RigidBody;
439
440 fn index(&self, index: crate::data::Index) -> &RigidBody {
441 &self.bodies[index]
442 }
443}
444
445#[cfg(not(feature = "dev-remove-slow-accessors"))]
446impl IndexMut<RigidBodyHandle> for RigidBodySet {
447 fn index_mut(&mut self, handle: RigidBodyHandle) -> &mut RigidBody {
448 let rb = &mut self.bodies[handle.0];
449 self.modified_bodies.push_once(handle, rb);
450 rb
451 }
452}