Skip to main content

rapier3d/geometry/
collider_set.rs

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