rapier3d/geometry/
collider_set.rs

1use crate::data::arena::Arena;
2use crate::data::{HasModifiedFlag, ModifiedObjects};
3use crate::dynamics::{IslandManager, RigidBodyHandle, RigidBodySet};
4use crate::geometry::{Collider, ColliderChanges, ColliderHandle, ColliderParent};
5use crate::math::Isometry;
6use std::ops::{Index, IndexMut};
7
8/// A set of modified colliders
9pub type ModifiedColliders = ModifiedObjects<ColliderHandle, Collider>;
10
11impl HasModifiedFlag for Collider {
12    #[inline]
13    fn has_modified_flag(&self) -> bool {
14        self.changes.contains(ColliderChanges::IN_MODIFIED_SET)
15    }
16
17    #[inline]
18    fn set_modified_flag(&mut self) {
19        self.changes |= ColliderChanges::IN_MODIFIED_SET;
20    }
21}
22
23#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
24#[derive(Clone, Default, Debug)]
25/// The collection that stores all colliders (collision shapes) in your physics world.
26///
27/// Similar to [`RigidBodySet`](crate::dynamics::RigidBodySet), this is the "database" where
28/// all your collision shapes live. Each collider can be attached to a rigid body or exist
29/// independently.
30///
31/// # Example
32/// ```
33/// # use rapier3d::prelude::*;
34/// let mut colliders = ColliderSet::new();
35/// # let mut bodies = RigidBodySet::new();
36/// # let body_handle = bodies.insert(RigidBodyBuilder::dynamic());
37///
38/// // Add a standalone collider (no parent body)
39/// let handle = colliders.insert(ColliderBuilder::ball(0.5));
40///
41/// // Or attach it to a body
42/// let handle = colliders.insert_with_parent(
43///     ColliderBuilder::cuboid(1.0, 1.0, 1.0),
44///     body_handle,
45///     &mut bodies
46/// );
47/// ```
48pub struct ColliderSet {
49    pub(crate) colliders: Arena<Collider>,
50    pub(crate) modified_colliders: ModifiedColliders,
51    pub(crate) removed_colliders: Vec<ColliderHandle>,
52}
53
54impl ColliderSet {
55    /// Creates a new empty collection of colliders.
56    pub fn new() -> Self {
57        ColliderSet {
58            colliders: Arena::new(),
59            modified_colliders: Default::default(),
60            removed_colliders: Vec::new(),
61        }
62    }
63
64    /// Creates a new collection with pre-allocated space for the given number of colliders.
65    ///
66    /// Use this if you know approximately how many colliders you'll need.
67    pub fn with_capacity(capacity: usize) -> Self {
68        ColliderSet {
69            colliders: Arena::with_capacity(capacity),
70            modified_colliders: ModifiedColliders::with_capacity(capacity),
71            removed_colliders: Vec::new(),
72        }
73    }
74
75    /// Fetch the set of colliders modified since the last call to
76    /// `take_modified`
77    ///
78    /// Provides a value that can be passed to the `modified_colliders` argument
79    /// of [`BroadPhaseBvh::update`](crate::geometry::BroadPhaseBvh::update).
80    ///
81    /// Should not be used if this [`ColliderSet`] will be used with a
82    /// [`PhysicsPipeline`](crate::pipeline::PhysicsPipeline), which handles
83    /// broadphase updates automatically.
84    pub fn take_modified(&mut self) -> ModifiedColliders {
85        std::mem::take(&mut self.modified_colliders)
86    }
87
88    pub(crate) fn set_modified(&mut self, modified: ModifiedColliders) {
89        self.modified_colliders = modified;
90    }
91
92    /// Fetch the set of colliders removed since the last call to `take_removed`
93    ///
94    /// Provides a value that can be passed to the `removed_colliders` argument
95    /// of [`BroadPhaseBvh::update`](crate::geometry::BroadPhaseBvh::update).
96    ///
97    /// Should not be used if this [`ColliderSet`] will be used with a
98    /// [`PhysicsPipeline`](crate::pipeline::PhysicsPipeline), which handles
99    /// broadphase updates automatically.
100    pub fn take_removed(&mut self) -> Vec<ColliderHandle> {
101        std::mem::take(&mut self.removed_colliders)
102    }
103
104    /// Returns a handle that's guaranteed to be invalid.
105    ///
106    /// Useful as a sentinel/placeholder value.
107    pub fn invalid_handle() -> ColliderHandle {
108        ColliderHandle::from_raw_parts(crate::INVALID_U32, crate::INVALID_U32)
109    }
110
111    /// Iterates over all colliders in this collection.
112    ///
113    /// Yields `(handle, &Collider)` pairs for each collider (including disabled ones).
114    pub fn iter(&self) -> impl ExactSizeIterator<Item = (ColliderHandle, &Collider)> {
115        self.colliders.iter().map(|(h, c)| (ColliderHandle(h), c))
116    }
117
118    /// Iterates over only the enabled colliders.
119    ///
120    /// Disabled colliders are excluded from physics simulation and queries.
121    pub fn iter_enabled(&self) -> impl Iterator<Item = (ColliderHandle, &Collider)> {
122        self.colliders
123            .iter()
124            .map(|(h, c)| (ColliderHandle(h), c))
125            .filter(|(_, c)| c.is_enabled())
126    }
127
128    /// Iterates over all colliders with mutable access.
129    #[cfg(not(feature = "dev-remove-slow-accessors"))]
130    pub fn iter_mut(&mut self) -> impl Iterator<Item = (ColliderHandle, &mut Collider)> {
131        self.modified_colliders.clear();
132        let modified_colliders = &mut self.modified_colliders;
133        self.colliders.iter_mut().map(move |(h, co)| {
134            // NOTE: we push unchecked here since we are just re-populating the
135            //       `modified_colliders` set that we just cleared before iteration.
136            modified_colliders.push_unchecked(ColliderHandle(h), co);
137            (ColliderHandle(h), co)
138        })
139    }
140
141    /// Iterates over only the enabled colliders with mutable access.
142    #[cfg(not(feature = "dev-remove-slow-accessors"))]
143    pub fn iter_enabled_mut(&mut self) -> impl Iterator<Item = (ColliderHandle, &mut Collider)> {
144        self.iter_mut().filter(|(_, c)| c.is_enabled())
145    }
146
147    /// Returns how many colliders are currently in this collection.
148    pub fn len(&self) -> usize {
149        self.colliders.len()
150    }
151
152    /// Returns `true` if there are no colliders in this collection.
153    pub fn is_empty(&self) -> bool {
154        self.colliders.is_empty()
155    }
156
157    /// Checks if the given handle points to a valid collider that still exists.
158    pub fn contains(&self, handle: ColliderHandle) -> bool {
159        self.colliders.contains(handle.0)
160    }
161
162    /// Adds a standalone collider (not attached to any body) and returns its handle.
163    ///
164    /// Most colliders should be attached to rigid bodies using [`insert_with_parent()`](Self::insert_with_parent) instead.
165    /// Standalone colliders are useful for sensors or static collision geometry that doesn't need a body.
166    pub fn insert(&mut self, coll: impl Into<Collider>) -> ColliderHandle {
167        let mut coll = coll.into();
168        // Make sure the internal links are reset, they may not be
169        // if this rigid-body was obtained by cloning another one.
170        coll.reset_internal_references();
171        coll.parent = None;
172        let handle = ColliderHandle(self.colliders.insert(coll));
173        // NOTE: we push unchecked because this is a brand-new collider
174        //       so it was initialized with the changed flag but isn’t in
175        //       the set yet.
176        self.modified_colliders
177            .push_unchecked(handle, &mut self.colliders[handle.0]);
178        handle
179    }
180
181    /// Adds a collider attached to a rigid body and returns its handle.
182    ///
183    /// This is the most common way to add colliders. The collider's position is relative
184    /// to its parent body, so when the body moves, the collider moves with it.
185    ///
186    /// # Example
187    /// ```
188    /// # use rapier3d::prelude::*;
189    /// # let mut colliders = ColliderSet::new();
190    /// # let mut bodies = RigidBodySet::new();
191    /// # let body_handle = bodies.insert(RigidBodyBuilder::dynamic());
192    /// // Create a ball collider attached to a dynamic body
193    /// let collider_handle = colliders.insert_with_parent(
194    ///     ColliderBuilder::ball(0.5),
195    ///     body_handle,
196    ///     &mut bodies
197    /// );
198    /// ```
199    pub fn insert_with_parent(
200        &mut self,
201        coll: impl Into<Collider>,
202        parent_handle: RigidBodyHandle,
203        bodies: &mut RigidBodySet,
204    ) -> ColliderHandle {
205        let mut coll = coll.into();
206        // Make sure the internal links are reset, they may not be
207        // if this collider was obtained by cloning another one.
208        coll.reset_internal_references();
209
210        if let Some(prev_parent) = &mut coll.parent {
211            prev_parent.handle = parent_handle;
212        } else {
213            coll.parent = Some(ColliderParent {
214                handle: parent_handle,
215                pos_wrt_parent: coll.pos.0,
216            });
217        }
218
219        // NOTE: we use `get_mut` instead of `get_mut_internal` so that the
220        // modification flag is updated properly.
221        let parent = bodies
222            .get_mut_internal_with_modification_tracking(parent_handle)
223            .expect("Parent rigid body not found.");
224        let handle = ColliderHandle(self.colliders.insert(coll));
225        let coll = self.colliders.get_mut(handle.0).unwrap();
226        // NOTE: we push unchecked because this is a brand-new collider
227        //       so it was initialized with the changed flag but isn’t in
228        //       the set yet.
229        self.modified_colliders.push_unchecked(handle, coll);
230
231        parent.add_collider_internal(
232            handle,
233            coll.parent.as_mut().unwrap(),
234            &mut coll.pos,
235            &coll.shape,
236            &coll.mprops,
237        );
238        handle
239    }
240
241    /// Changes which rigid body a collider is attached to, or detaches it completely.
242    ///
243    /// Use this to move a collider from one body to another, or to make it standalone.
244    ///
245    /// # Parameters
246    /// * `new_parent_handle` - `Some(handle)` to attach to a body, `None` to make standalone
247    ///
248    /// # Example
249    /// ```
250    /// # use rapier3d::prelude::*;
251    /// # let mut colliders = ColliderSet::new();
252    /// # let mut bodies = RigidBodySet::new();
253    /// # let body_handle = bodies.insert(RigidBodyBuilder::dynamic());
254    /// # let other_body = bodies.insert(RigidBodyBuilder::dynamic());
255    /// # let collider_handle = colliders.insert_with_parent(ColliderBuilder::ball(0.5).build(), body_handle, &mut bodies);
256    /// // Detach collider from its current body
257    /// colliders.set_parent(collider_handle, None, &mut bodies);
258    ///
259    /// // Attach it to a different body
260    /// colliders.set_parent(collider_handle, Some(other_body), &mut bodies);
261    /// ```
262    pub fn set_parent(
263        &mut self,
264        handle: ColliderHandle,
265        new_parent_handle: Option<RigidBodyHandle>,
266        bodies: &mut RigidBodySet,
267    ) {
268        if let Some(collider) = self.get_mut(handle) {
269            let curr_parent = collider.parent.map(|p| p.handle);
270            if new_parent_handle == curr_parent {
271                return; // Nothing to do, this is the same parent.
272            }
273
274            collider.changes |= ColliderChanges::PARENT;
275
276            if let Some(parent_handle) = curr_parent {
277                if let Some(rb) = bodies.get_mut(parent_handle) {
278                    rb.remove_collider_internal(handle);
279                }
280            }
281
282            match new_parent_handle {
283                Some(new_parent_handle) => {
284                    if let Some(parent) = &mut collider.parent {
285                        parent.handle = new_parent_handle;
286                    } else {
287                        collider.parent = Some(ColliderParent {
288                            handle: new_parent_handle,
289                            pos_wrt_parent: Isometry::identity(),
290                        })
291                    };
292
293                    if let Some(rb) = bodies.get_mut(new_parent_handle) {
294                        rb.add_collider_internal(
295                            handle,
296                            collider.parent.as_ref().unwrap(),
297                            &mut collider.pos,
298                            &collider.shape,
299                            &collider.mprops,
300                        );
301                    }
302                }
303                None => collider.parent = None,
304            }
305        }
306    }
307
308    /// Removes a collider from the world.
309    ///
310    /// The collider is detached from its parent body (if any) and removed from all
311    /// collision detection structures. Returns the removed collider if it existed.
312    ///
313    /// # Parameters
314    /// * `wake_up` - If `true`, wakes up the parent body (useful when collider removal
315    ///   changes the body's mass or collision behavior significantly)
316    ///
317    /// # Example
318    /// ```
319    /// # use rapier3d::prelude::*;
320    /// # let mut colliders = ColliderSet::new();
321    /// # let mut bodies = RigidBodySet::new();
322    /// # let mut islands = IslandManager::new();
323    /// # let body_handle = bodies.insert(RigidBodyBuilder::dynamic().build());
324    /// # let handle = colliders.insert_with_parent(ColliderBuilder::ball(0.5).build(), body_handle, &mut bodies);
325    /// if let Some(collider) = colliders.remove(
326    ///     handle,
327    ///     &mut islands,
328    ///     &mut bodies,
329    ///     true  // Wake up the parent body
330    /// ) {
331    ///     println!("Removed collider with shape: {:?}", collider.shared_shape());
332    /// }
333    /// ```
334    pub fn remove(
335        &mut self,
336        handle: ColliderHandle,
337        islands: &mut IslandManager,
338        bodies: &mut RigidBodySet,
339        wake_up: bool,
340    ) -> Option<Collider> {
341        let collider = self.colliders.remove(handle.0)?;
342
343        /*
344         * Delete the collider from its parent body.
345         */
346        // NOTE: we use `get_mut_internal_with_modification_tracking` instead of `get_mut_internal` so that the
347        // modification flag is updated properly.
348        if let Some(parent) = &collider.parent {
349            if let Some(parent_rb) =
350                bodies.get_mut_internal_with_modification_tracking(parent.handle)
351            {
352                parent_rb.remove_collider_internal(handle);
353
354                if wake_up {
355                    islands.wake_up(bodies, parent.handle, true);
356                }
357            }
358        }
359
360        /*
361         * Publish removal.
362         */
363        self.removed_colliders.push(handle);
364
365        Some(collider)
366    }
367
368    /// Gets a collider by its index without knowing the generation number.
369    ///
370    /// ⚠️ **Advanced/unsafe usage** - prefer [`get()`](Self::get) instead! See [`RigidBodySet::get_unknown_gen`] for details.
371    pub fn get_unknown_gen(&self, i: u32) -> Option<(&Collider, ColliderHandle)> {
372        self.colliders
373            .get_unknown_gen(i)
374            .map(|(c, h)| (c, ColliderHandle(h)))
375    }
376
377    /// Gets a mutable reference to a collider by its index without knowing the generation.
378    ///
379    /// ⚠️ **Advanced/unsafe usage** - prefer [`get_mut()`](Self::get_mut) instead!
380    /// suffer form the ABA problem.
381    #[cfg(not(feature = "dev-remove-slow-accessors"))]
382    pub fn get_unknown_gen_mut(&mut self, i: u32) -> Option<(&mut Collider, ColliderHandle)> {
383        let (collider, handle) = self.colliders.get_unknown_gen_mut(i)?;
384        let handle = ColliderHandle(handle);
385        self.modified_colliders.push_once(handle, collider);
386        Some((collider, handle))
387    }
388
389    /// Gets a read-only reference to the collider with the given handle.
390    ///
391    /// Returns `None` if the handle is invalid or the collider was removed.
392    pub fn get(&self, handle: ColliderHandle) -> Option<&Collider> {
393        self.colliders.get(handle.0)
394    }
395
396    /// Gets a mutable reference to the collider with the given handle.
397    ///
398    /// Returns `None` if the handle is invalid or the collider was removed.
399    /// Use this to modify collider properties like friction, restitution, sensor status, etc.
400    #[cfg(not(feature = "dev-remove-slow-accessors"))]
401    pub fn get_mut(&mut self, handle: ColliderHandle) -> Option<&mut Collider> {
402        let result = self.colliders.get_mut(handle.0)?;
403        self.modified_colliders.push_once(handle, result);
404        Some(result)
405    }
406
407    /// Gets mutable references to two different colliders at once.
408    ///
409    /// Useful when you need to modify two colliders simultaneously. If both handles
410    /// are the same, only the first value will be `Some`.
411    #[cfg(not(feature = "dev-remove-slow-accessors"))]
412    pub fn get_pair_mut(
413        &mut self,
414        handle1: ColliderHandle,
415        handle2: ColliderHandle,
416    ) -> (Option<&mut Collider>, Option<&mut Collider>) {
417        if handle1 == handle2 {
418            (self.get_mut(handle1), None)
419        } else {
420            let (mut co1, mut co2) = self.colliders.get2_mut(handle1.0, handle2.0);
421            if let Some(co1) = co1.as_deref_mut() {
422                self.modified_colliders.push_once(handle1, co1);
423            }
424            if let Some(co2) = co2.as_deref_mut() {
425                self.modified_colliders.push_once(handle2, co2);
426            }
427            (co1, co2)
428        }
429    }
430
431    pub(crate) fn index_mut_internal(&mut self, handle: ColliderHandle) -> &mut Collider {
432        &mut self.colliders[handle.0]
433    }
434
435    pub(crate) fn get_mut_internal(&mut self, handle: ColliderHandle) -> Option<&mut Collider> {
436        self.colliders.get_mut(handle.0)
437    }
438
439    // Just a very long name instead of `.get_mut` to make sure
440    // this is really the method we wanted to use instead of `get_mut_internal`.
441    #[allow(dead_code)]
442    pub(crate) fn get_mut_internal_with_modification_tracking(
443        &mut self,
444        handle: ColliderHandle,
445    ) -> Option<&mut Collider> {
446        let result = self.colliders.get_mut(handle.0)?;
447        self.modified_colliders.push_once(handle, result);
448        Some(result)
449    }
450}
451
452impl Index<crate::data::Index> for ColliderSet {
453    type Output = Collider;
454
455    fn index(&self, index: crate::data::Index) -> &Collider {
456        &self.colliders[index]
457    }
458}
459
460impl Index<ColliderHandle> for ColliderSet {
461    type Output = Collider;
462
463    fn index(&self, index: ColliderHandle) -> &Collider {
464        &self.colliders[index.0]
465    }
466}
467
468#[cfg(not(feature = "dev-remove-slow-accessors"))]
469impl IndexMut<ColliderHandle> for ColliderSet {
470    fn index_mut(&mut self, handle: ColliderHandle) -> &mut Collider {
471        let collider = &mut self.colliders[handle.0];
472        self.modified_colliders.push_once(handle, collider);
473        collider
474    }
475}