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}