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}