Skip to main content

rapier2d/dynamics/
rigid_body_set.rs

1use crate::data::{Arena, HasModifiedFlag, ModifiedObjects};
2use crate::dynamics::{
3    ImpulseJointSet, IslandManager, MultibodyJointSet, RigidBody, RigidBodyBuilder,
4    RigidBodyChanges, RigidBodyHandle, SoftBodySet,
5};
6use crate::geometry::ColliderSet;
7use core::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::IN_MODIFIED_SET)
35    }
36
37    #[inline]
38    fn set_modified_flag(&mut self) {
39        self.changes |= RigidBodyChanges::IN_MODIFIED_SET;
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::new(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        core::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::new(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    /// # let mut soft_bodies = SoftBodySet::new();
189    /// // Remove a body and everything attached to it
190    /// if let Some(body) = bodies.remove(
191    ///     handle,
192    ///     &mut islands,
193    ///     &mut colliders,
194    ///     &mut impulse_joints,
195    ///     &mut multibody_joints,
196    ///     &mut soft_bodies,
197    ///     true  // Remove colliders too
198    /// ) {
199    ///     println!("Removed body at {:?}", body.translation());
200    /// }
201    /// ```
202    #[profiling::function]
203    pub fn remove(
204        &mut self,
205        handle: RigidBodyHandle,
206        islands: &mut IslandManager,
207        colliders: &mut ColliderSet,
208        impulse_joints: &mut ImpulseJointSet,
209        multibody_joints: &mut MultibodyJointSet,
210        soft_bodies: &mut SoftBodySet,
211        remove_attached_colliders: bool,
212    ) -> Option<RigidBody> {
213        // Removing a soft-frame proxy removes its cluster: the particles only it covers, the
214        // elements attached to them, and their colliders. Dissolved before the body removal so the
215        // proxy (and its parenting of the cluster's colliders) is still intact meanwhile.
216        if let Some(rb) = self.bodies.get(handle.0) {
217            if let (Some(sb_handle), Some(cluster)) = (rb.soft_body(), rb.soft_cluster()) {
218                soft_bodies.on_proxy_removed(sb_handle, cluster, islands, self, colliders);
219            }
220        }
221
222        let rb = self.bodies.remove(handle.0)?;
223        /*
224         * Update active sets.
225         */
226        islands.rigid_body_removed_or_disabled(handle, &rb.ids, self);
227
228        /*
229         * Remove colliders attached to this rigid-body.
230         */
231        if remove_attached_colliders {
232            for collider in rb.colliders() {
233                colliders.remove(*collider, islands, self, soft_bodies, false);
234            }
235        } else {
236            // If we don’t remove the attached colliders, simply detach them.
237            let colliders_to_detach = rb.colliders().to_vec();
238            for co_handle in colliders_to_detach {
239                colliders.set_parent(co_handle, None, self);
240            }
241        }
242
243        /*
244         * Remove impulse_joints attached to this rigid-body.
245         */
246        impulse_joints.remove_joints_attached_to_rigid_body(handle);
247        multibody_joints.remove_joints_attached_to_rigid_body(handle);
248
249        Some(rb)
250    }
251
252    /// Gets a rigid body by its index without knowing the generation number.
253    ///
254    /// ⚠️ **Advanced/unsafe usage** - prefer [`get()`](Self::get) instead!
255    ///
256    /// This bypasses the generation check that normally protects against the ABA problem
257    /// (where an index gets reused after removal). Only use this if you're certain the
258    /// body at this index is the one you expect.
259    ///
260    /// Returns both the body and its current handle (with the correct generation).
261    pub fn get_unknown_gen(&self, i: u32) -> Option<(&RigidBody, RigidBodyHandle)> {
262        self.bodies
263            .get_unknown_gen(i)
264            .map(|(b, h)| (b, RigidBodyHandle(h)))
265    }
266
267    /// Gets a mutable reference to a rigid body by its index without knowing the generation.
268    ///
269    /// ⚠️ **Advanced/unsafe usage** - prefer [`get_mut()`](Self::get_mut) instead!
270    ///
271    /// This bypasses the generation check. See [`get_unknown_gen()`](Self::get_unknown_gen)
272    /// for more details on when this is appropriate (rarely).
273    #[cfg(not(feature = "dev-remove-slow-accessors"))]
274    pub fn get_unknown_gen_mut(&mut self, i: u32) -> Option<(&mut RigidBody, RigidBodyHandle)> {
275        let (rb, handle) = self.bodies.get_unknown_gen_mut(i)?;
276        let handle = RigidBodyHandle(handle);
277        self.modified_bodies.push_once(handle, rb);
278        Some((rb, handle))
279    }
280
281    /// Gets a read-only reference to the rigid body with the given handle.
282    ///
283    /// Returns `None` if the handle is invalid or the body was removed.
284    ///
285    /// Use this to read body properties like position, velocity, mass, etc.
286    pub fn get(&self, handle: RigidBodyHandle) -> Option<&RigidBody> {
287        self.bodies.get(handle.0)
288    }
289
290    /// Gets a mutable reference to the rigid body with the given handle.
291    ///
292    /// Returns `None` if the handle is invalid or the body was removed.
293    ///
294    /// Use this to modify body properties, apply forces/impulses, change velocities, etc.
295    ///
296    /// # Example
297    /// ```
298    /// # use rapier3d::prelude::*;
299    /// # let mut bodies = RigidBodySet::new();
300    /// # let handle = bodies.insert(RigidBodyBuilder::dynamic());
301    /// if let Some(body) = bodies.get_mut(handle) {
302    ///     body.set_linvel(Vector::new(1.0, 0.0, 0.0), true);
303    ///     body.apply_impulse(Vector::new(0.0, 100.0, 0.0), true);
304    /// }
305    /// ```
306    #[cfg(not(feature = "dev-remove-slow-accessors"))]
307    pub fn get_mut(&mut self, handle: RigidBodyHandle) -> Option<&mut RigidBody> {
308        let result = self.bodies.get_mut(handle.0)?;
309        self.modified_bodies.push_once(handle, result);
310        Some(result)
311    }
312
313    /// Gets mutable references to two different rigid bodies at once.
314    ///
315    /// This is useful when you need to modify two bodies simultaneously (e.g., when manually
316    /// handling collisions between them). If both handles are the same, only the first value
317    /// will be `Some`.
318    ///
319    /// # Example
320    /// ```
321    /// # use rapier3d::prelude::*;
322    /// # let mut bodies = RigidBodySet::new();
323    /// # let handle1 = bodies.insert(RigidBodyBuilder::dynamic());
324    /// # let handle2 = bodies.insert(RigidBodyBuilder::dynamic());
325    /// let (body1, body2) = bodies.get_pair_mut(handle1, handle2);
326    /// if let (Some(b1), Some(b2)) = (body1, body2) {
327    ///     // Can modify both bodies at once
328    ///     b1.apply_impulse(Vector::new(10.0, 0.0, 0.0), true);
329    ///     b2.apply_impulse(Vector::new(-10.0, 0.0, 0.0), true);
330    /// }
331    /// ```
332    #[cfg(not(feature = "dev-remove-slow-accessors"))]
333    pub fn get_pair_mut(
334        &mut self,
335        handle1: RigidBodyHandle,
336        handle2: RigidBodyHandle,
337    ) -> (Option<&mut RigidBody>, Option<&mut RigidBody>) {
338        if handle1 == handle2 {
339            (self.get_mut(handle1), None)
340        } else {
341            let (mut rb1, mut rb2) = self.bodies.get2_mut(handle1.0, handle2.0);
342            if let Some(rb1) = rb1.as_deref_mut() {
343                self.modified_bodies.push_once(handle1, rb1);
344            }
345            if let Some(rb2) = rb2.as_deref_mut() {
346                self.modified_bodies.push_once(handle2, rb2);
347            }
348            (rb1, rb2)
349        }
350    }
351
352    pub(crate) fn get_mut_internal(&mut self, handle: RigidBodyHandle) -> Option<&mut RigidBody> {
353        self.bodies.get_mut(handle.0)
354    }
355
356    pub(crate) fn index_mut_internal(&mut self, handle: RigidBodyHandle) -> &mut RigidBody {
357        &mut self.bodies[handle.0]
358    }
359
360    // Just a very long name instead of `.get_mut` to make sure
361    // this is really the method we wanted to use instead of `get_mut_internal`.
362    pub(crate) fn get_mut_internal_with_modification_tracking(
363        &mut self,
364        handle: RigidBodyHandle,
365    ) -> Option<&mut RigidBody> {
366        let result = self.bodies.get_mut(handle.0)?;
367        self.modified_bodies.push_once(handle, result);
368        Some(result)
369    }
370
371    /// Iterates over all rigid bodies in this collection.
372    ///
373    /// Each iteration yields a `(handle, &RigidBody)` pair. Use this to read properties
374    /// of all bodies (positions, velocities, etc.) without modifying them.
375    ///
376    /// # Example
377    /// ```
378    /// # use rapier3d::prelude::*;
379    /// # let mut bodies = RigidBodySet::new();
380    /// # bodies.insert(RigidBodyBuilder::dynamic());
381    /// for (handle, body) in bodies.iter() {
382    ///     println!("Body {:?} is at {:?}", handle, body.translation());
383    /// }
384    /// ```
385    pub fn iter(&self) -> impl Iterator<Item = (RigidBodyHandle, &RigidBody)> {
386        self.bodies.iter().map(|(h, b)| (RigidBodyHandle(h), b))
387    }
388
389    /// Iterates over all rigid bodies with mutable access.
390    ///
391    /// Each iteration yields a `(handle, &mut RigidBody)` pair. Use this to modify
392    /// multiple bodies in one pass.
393    ///
394    /// # Example
395    /// ```
396    /// # use rapier3d::prelude::*;
397    /// # let mut bodies = RigidBodySet::new();
398    /// # bodies.insert(RigidBodyBuilder::dynamic());
399    /// // Apply gravity manually to all dynamic bodies
400    /// for (handle, body) in bodies.iter_mut() {
401    ///     if body.is_dynamic() {
402    ///         body.add_force(Vector::new(0.0, -9.81 * body.mass(), 0.0), true);
403    ///     }
404    /// }
405    /// ```
406    #[cfg(not(feature = "dev-remove-slow-accessors"))]
407    pub fn iter_mut(&mut self) -> impl Iterator<Item = (RigidBodyHandle, &mut RigidBody)> {
408        self.modified_bodies.clear();
409        let modified_bodies = &mut self.modified_bodies;
410        self.bodies.iter_mut().map(move |(h, b)| {
411            // NOTE: using `push_unchecked` because we just cleared `modified_bodies`
412            //       before iterating.
413            modified_bodies.push_unchecked(RigidBodyHandle(h), b);
414            (RigidBodyHandle(h), b)
415        })
416    }
417
418    /// Updates the positions of all colliders attached to bodies that have moved.
419    ///
420    /// Normally you don't need to call this - it's automatically handled by [`PhysicsPipeline::step`].
421    /// Only call this manually if you're:
422    /// - Moving bodies yourself outside of `step()`
423    /// - Using `QueryPipeline` for raycasts without running physics simulation
424    /// - Need collider positions to be immediately up-to-date for some custom logic
425    ///
426    /// This synchronizes collider world positions based on their parent bodies' positions.
427    pub fn propagate_modified_body_positions_to_colliders(&self, colliders: &mut ColliderSet) {
428        for body in self.modified_bodies.iter().filter_map(|h| self.get(*h)) {
429            if body.changes.contains(RigidBodyChanges::POSITION) {
430                for handle in body.colliders() {
431                    if let Some(collider) = colliders.get_mut(*handle) {
432                        let new_pos = body.position() * collider.position_wrt_parent().unwrap();
433                        collider.set_position(new_pos);
434                    }
435                }
436            }
437        }
438    }
439}
440
441impl Index<RigidBodyHandle> for RigidBodySet {
442    type Output = RigidBody;
443
444    fn index(&self, index: RigidBodyHandle) -> &RigidBody {
445        &self.bodies[index.0]
446    }
447}
448
449impl Index<crate::data::Index> for RigidBodySet {
450    type Output = RigidBody;
451
452    fn index(&self, index: crate::data::Index) -> &RigidBody {
453        &self.bodies[index]
454    }
455}
456
457#[cfg(not(feature = "dev-remove-slow-accessors"))]
458impl IndexMut<RigidBodyHandle> for RigidBodySet {
459    fn index_mut(&mut self, handle: RigidBodyHandle) -> &mut RigidBody {
460        let rb = &mut self.bodies[handle.0];
461        self.modified_bodies.push_once(handle, rb);
462        rb
463    }
464}