rapier2d/geometry/collider_set.rs
1use crate::alloc_prelude::*;
2use crate::data::arena::Arena;
3use crate::data::{HasModifiedFlag, ModifiedObjects};
4use crate::dynamics::{
5 IslandManager, RigidBodyHandle, RigidBodySet, SoftBindingError, SoftBodySet, SoftMeshBinding,
6};
7use crate::geometry::{Collider, ColliderChanges, ColliderHandle, ColliderParent};
8use crate::math::{DIM, Pose, Vector};
9use core::ops::{Index, IndexMut};
10
11/// A set of modified colliders
12pub type ModifiedColliders = ModifiedObjects<ColliderHandle, Collider>;
13
14impl HasModifiedFlag for Collider {
15 #[inline]
16 fn has_modified_flag(&self) -> bool {
17 self.changes.contains(ColliderChanges::IN_MODIFIED_SET)
18 }
19
20 #[inline]
21 fn set_modified_flag(&mut self) {
22 self.changes |= ColliderChanges::IN_MODIFIED_SET;
23 }
24}
25
26#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
27#[derive(Clone, Default, Debug)]
28/// The collection that stores all colliders (collision shapes) in your physics world.
29///
30/// Similar to [`RigidBodySet`](crate::dynamics::RigidBodySet), this is the "database" where
31/// all your collision shapes live. Each collider can be attached to a rigid body or exist
32/// independently.
33///
34/// # Example
35/// ```
36/// # use rapier3d::prelude::*;
37/// let mut colliders = ColliderSet::new();
38/// # let mut bodies = RigidBodySet::new();
39/// # let body_handle = bodies.insert(RigidBodyBuilder::dynamic());
40///
41/// // Add a standalone collider (no parent body)
42/// let handle = colliders.insert(ColliderBuilder::ball(0.5));
43///
44/// // Or attach it to a body
45/// let handle = colliders.insert_with_parent(
46/// ColliderBuilder::cuboid(1.0, 1.0, 1.0),
47/// body_handle,
48/// &mut bodies
49/// );
50/// ```
51pub struct ColliderSet {
52 pub(crate) colliders: Arena<Collider>,
53 pub(crate) modified_colliders: ModifiedColliders,
54 pub(crate) removed_colliders: Vec<ColliderHandle>,
55}
56
57impl ColliderSet {
58 /// Creates a new empty collection of colliders.
59 pub fn new() -> Self {
60 ColliderSet {
61 colliders: Arena::new(),
62 modified_colliders: Default::default(),
63 removed_colliders: Vec::new(),
64 }
65 }
66
67 /// Creates a new collection with pre-allocated space for the given number of colliders.
68 ///
69 /// Use this if you know approximately how many colliders you'll need.
70 pub fn with_capacity(capacity: usize) -> Self {
71 ColliderSet {
72 colliders: Arena::with_capacity(capacity),
73 modified_colliders: ModifiedColliders::with_capacity(capacity),
74 removed_colliders: Vec::new(),
75 }
76 }
77
78 /// Fetch the set of colliders modified since the last call to
79 /// `take_modified`
80 ///
81 /// Provides a value that can be passed to the `modified_colliders` argument
82 /// of [`BroadPhaseBvh::update`](crate::geometry::BroadPhaseBvh::update).
83 ///
84 /// Should not be used if this [`ColliderSet`] will be used with a
85 /// [`PhysicsPipeline`](crate::pipeline::PhysicsPipeline), which handles
86 /// broadphase updates automatically.
87 pub fn take_modified(&mut self) -> ModifiedColliders {
88 core::mem::take(&mut self.modified_colliders)
89 }
90
91 pub(crate) fn set_modified(&mut self, modified: ModifiedColliders) {
92 self.modified_colliders = modified;
93 }
94
95 /// Fetch the set of colliders removed since the last call to `take_removed`
96 ///
97 /// Provides a value that can be passed to the `removed_colliders` argument
98 /// of [`BroadPhaseBvh::update`](crate::geometry::BroadPhaseBvh::update).
99 ///
100 /// Should not be used if this [`ColliderSet`] will be used with a
101 /// [`PhysicsPipeline`](crate::pipeline::PhysicsPipeline), which handles
102 /// broadphase updates automatically.
103 pub fn take_removed(&mut self) -> Vec<ColliderHandle> {
104 core::mem::take(&mut self.removed_colliders)
105 }
106
107 /// Returns a handle that's guaranteed to be invalid.
108 ///
109 /// Useful as a sentinel/placeholder value.
110 pub fn invalid_handle() -> ColliderHandle {
111 ColliderHandle::from_raw_parts(crate::INVALID_U32, crate::INVALID_U32)
112 }
113
114 /// Iterates over all colliders in this collection.
115 ///
116 /// Yields `(handle, &Collider)` pairs for each collider (including disabled ones).
117 pub fn iter(&self) -> impl ExactSizeIterator<Item = (ColliderHandle, &Collider)> {
118 self.colliders.iter().map(|(h, c)| (ColliderHandle(h), c))
119 }
120
121 /// Iterates over only the enabled colliders.
122 ///
123 /// Disabled colliders are excluded from physics simulation and queries.
124 pub fn iter_enabled(&self) -> impl Iterator<Item = (ColliderHandle, &Collider)> {
125 self.colliders
126 .iter()
127 .map(|(h, c)| (ColliderHandle(h), c))
128 .filter(|(_, c)| c.is_enabled())
129 }
130
131 /// Iterates over all colliders with mutable access.
132 #[cfg(not(feature = "dev-remove-slow-accessors"))]
133 pub fn iter_mut(&mut self) -> impl Iterator<Item = (ColliderHandle, &mut Collider)> {
134 self.modified_colliders.clear();
135 let modified_colliders = &mut self.modified_colliders;
136 self.colliders.iter_mut().map(move |(h, co)| {
137 // NOTE: we push unchecked here since we are just re-populating the
138 // `modified_colliders` set that we just cleared before iteration.
139 modified_colliders.push_unchecked(ColliderHandle(h), co);
140 (ColliderHandle(h), co)
141 })
142 }
143
144 /// Iterates over only the enabled colliders with mutable access.
145 #[cfg(not(feature = "dev-remove-slow-accessors"))]
146 pub fn iter_enabled_mut(&mut self) -> impl Iterator<Item = (ColliderHandle, &mut Collider)> {
147 self.iter_mut().filter(|(_, c)| c.is_enabled())
148 }
149
150 /// Returns how many colliders are currently in this collection.
151 pub fn len(&self) -> usize {
152 self.colliders.len()
153 }
154
155 /// Returns `true` if there are no colliders in this collection.
156 pub fn is_empty(&self) -> bool {
157 self.colliders.is_empty()
158 }
159
160 /// Checks if the given handle points to a valid collider that still exists.
161 pub fn contains(&self, handle: ColliderHandle) -> bool {
162 self.colliders.contains(handle.0)
163 }
164
165 /// Adds a standalone collider (not attached to any body) and returns its handle.
166 ///
167 /// Most colliders should be attached to rigid bodies using [`insert_with_parent()`](Self::insert_with_parent) instead.
168 /// Standalone colliders are useful for sensors or static collision geometry that doesn't need a body.
169 pub fn insert(&mut self, coll: impl Into<Collider>) -> ColliderHandle {
170 let mut coll = coll.into();
171 // Make sure the internal links are reset, they may not be
172 // if this rigid-body was obtained by cloning another one.
173 coll.reset_internal_references();
174 coll.parent = None;
175 let handle = ColliderHandle(self.colliders.insert(coll));
176 // NOTE: we push unchecked because this is a brand-new collider
177 // so it was initialized with the changed flag but isn’t in
178 // the set yet.
179 self.modified_colliders
180 .push_unchecked(handle, &mut self.colliders[handle.0]);
181 handle
182 }
183
184 /// Adds a collider attached to a rigid body and returns its handle.
185 ///
186 /// This is the most common way to add colliders. The collider's position is relative
187 /// to its parent body, so when the body moves, the collider moves with it.
188 ///
189 /// # Example
190 /// ```
191 /// # use rapier3d::prelude::*;
192 /// # let mut colliders = ColliderSet::new();
193 /// # let mut bodies = RigidBodySet::new();
194 /// # let body_handle = bodies.insert(RigidBodyBuilder::dynamic());
195 /// // Create a ball collider attached to a dynamic body
196 /// let collider_handle = colliders.insert_with_parent(
197 /// ColliderBuilder::ball(0.5),
198 /// body_handle,
199 /// &mut bodies
200 /// );
201 /// ```
202 pub fn insert_with_parent(
203 &mut self,
204 coll: impl Into<Collider>,
205 parent_handle: RigidBodyHandle,
206 bodies: &mut RigidBodySet,
207 ) -> ColliderHandle {
208 let mut coll = coll.into();
209 // Make sure the internal links are reset, they may not be
210 // if this collider was obtained by cloning another one.
211 coll.reset_internal_references();
212
213 if let Some(prev_parent) = &mut coll.parent {
214 prev_parent.handle = parent_handle;
215 } else {
216 coll.parent = Some(ColliderParent {
217 handle: parent_handle,
218 pos_wrt_parent: coll.pos.0,
219 });
220 }
221
222 // NOTE: we use `get_mut` instead of `get_mut_internal` so that the
223 // modification flag is updated properly.
224 let parent = bodies
225 .get_mut_internal_with_modification_tracking(parent_handle)
226 .expect("Parent rigid body not found.");
227 let handle = ColliderHandle(self.colliders.insert(coll));
228 let coll = self.colliders.get_mut(handle.0).unwrap();
229 // NOTE: we push unchecked because this is a brand-new collider
230 // so it was initialized with the changed flag but isn’t in
231 // the set yet.
232 self.modified_colliders.push_unchecked(handle, coll);
233
234 parent.add_collider_internal(
235 handle,
236 coll.parent.as_mut().unwrap(),
237 &mut coll.pos,
238 &coll.shape,
239 &coll.mprops,
240 );
241 handle
242 }
243
244 /// Inserts a collider holding a soft body's deformable collision mesh: a polyline (2D) or
245 /// triangle mesh (3D) whose vertices follow the cluster proxy `parent_handle` via `binding`
246 /// ([`crate::dynamics::SoftBodyCluster::proxy`]); a failed call leaves both sets untouched.
247 pub fn insert_deformable(
248 &mut self,
249 coll: impl Into<Collider>,
250 binding: SoftMeshBinding,
251 parent_handle: RigidBodyHandle,
252 bodies: &mut RigidBodySet,
253 soft_bodies: &mut SoftBodySet,
254 ) -> Result<ColliderHandle, SoftBindingError> {
255 let mut coll = coll.into();
256 // The parent must be a live cluster proxy: it says which body and cluster the mesh
257 // joins, and its pose places the collider like any attached one.
258 let (body_handle, cluster_id, frame) = {
259 let rb = bodies
260 .get(parent_handle)
261 .ok_or(SoftBindingError::NotAClusterProxy)?;
262 let body = rb.soft_body().ok_or(SoftBindingError::NotAClusterProxy)?;
263 (body, rb.soft_cluster, rb.pos.position)
264 };
265 let sb = soft_bodies
266 .get_mut(body_handle)
267 .ok_or(SoftBindingError::NotAClusterProxy)?;
268 if sb
269 .cluster(cluster_id)
270 .is_none_or(|cluster| cluster.proxy() != parent_handle)
271 {
272 return Err(SoftBindingError::NotAClusterProxy);
273 }
274
275 let (vertices, indices) = mesh_geometry(coll.shape())?;
276 // The shape is kept as given, in the collider's own frame: the binding reads its
277 // vertices where the collider's pose relative to the proxy puts them.
278 let pos_wrt_parent = coll
279 .parent
280 .as_ref()
281 .map_or(coll.pos.0, |parent| parent.pos_wrt_parent);
282 let pose = frame * pos_wrt_parent;
283 let vertices: Vec<Vector> = vertices.iter().map(|v| pose * *v).collect();
284 let mut mesh = sb.bind_mesh(cluster_id, &binding, vertices, indices)?;
285 // The shape's `ORIENTED` flag says whether the closed mesh encloses solid matter.
286 #[cfg(feature = "dim2")]
287 let oriented = coll.shape().as_polyline().is_some_and(|polyline| {
288 polyline
289 .flags()
290 .contains(parry::shape::PolylineFlags::ORIENTED)
291 });
292 #[cfg(feature = "dim3")]
293 let oriented = coll.shape().as_trimesh().is_some_and(|trimesh| {
294 trimesh
295 .flags()
296 .contains(parry::shape::TriMeshFlags::ORIENTED)
297 });
298 mesh.oriented = oriented;
299 coll.set_density(0.0);
300 // The contact skin is the thickness of the mesh's vertices in the soft contact
301 // passes: a collider left without one gets the body's particle radius.
302 if coll.contact_skin() <= 0.0 {
303 coll.set_contact_skin(sb.particle_radius());
304 }
305
306 let id = sb.push_mesh(cluster_id, mesh);
307 let handle = self.insert_with_parent(coll, parent_handle, bodies);
308 let co = self.index_mut_internal(handle);
309 co.deformable_mesh_ref = Some(crate::dynamics::SoftMeshRef {
310 body: body_handle,
311 id,
312 });
313 soft_bodies[body_handle].set_mesh_collider(id, handle);
314 Ok(handle)
315 }
316
317 /// Changes which rigid body a collider is attached to, or detaches it completely.
318 ///
319 /// Use this to move a collider from one body to another, or to make it standalone.
320 ///
321 /// # Parameters
322 /// * `new_parent_handle` - `Some(handle)` to attach to a body, `None` to make standalone
323 ///
324 /// # Example
325 /// ```
326 /// # use rapier3d::prelude::*;
327 /// # let mut colliders = ColliderSet::new();
328 /// # let mut bodies = RigidBodySet::new();
329 /// # let body_handle = bodies.insert(RigidBodyBuilder::dynamic());
330 /// # let other_body = bodies.insert(RigidBodyBuilder::dynamic());
331 /// # let collider_handle = colliders.insert_with_parent(ColliderBuilder::ball(0.5).build(), body_handle, &mut bodies);
332 /// // Detach collider from its current body
333 /// colliders.set_parent(collider_handle, None, &mut bodies);
334 ///
335 /// // Attach it to a different body
336 /// colliders.set_parent(collider_handle, Some(other_body), &mut bodies);
337 /// ```
338 pub fn set_parent(
339 &mut self,
340 handle: ColliderHandle,
341 new_parent_handle: Option<RigidBodyHandle>,
342 bodies: &mut RigidBodySet,
343 ) {
344 if let Some(collider) = self.get_mut(handle) {
345 let curr_parent = collider.parent.map(|p| p.handle);
346 if new_parent_handle == curr_parent {
347 return; // Nothing to do, this is the same parent.
348 }
349
350 collider.changes |= ColliderChanges::PARENT;
351
352 if let Some(parent_handle) = curr_parent {
353 if let Some(rb) = bodies.get_mut(parent_handle) {
354 rb.remove_collider_internal(handle);
355 }
356 }
357
358 match new_parent_handle {
359 Some(new_parent_handle) => {
360 if let Some(parent) = &mut collider.parent {
361 parent.handle = new_parent_handle;
362 } else {
363 collider.parent = Some(ColliderParent {
364 handle: new_parent_handle,
365 pos_wrt_parent: Pose::IDENTITY,
366 })
367 };
368
369 if let Some(rb) = bodies.get_mut(new_parent_handle) {
370 rb.add_collider_internal(
371 handle,
372 collider.parent.as_ref().unwrap(),
373 &mut collider.pos,
374 &collider.shape,
375 &collider.mprops,
376 );
377 }
378 }
379 None => collider.parent = None,
380 }
381 }
382 }
383
384 /// Removes a collider from the world.
385 ///
386 /// The collider is detached from its parent body (if any) and removed from all
387 /// collision detection structures. Returns the removed collider if it existed.
388 ///
389 /// # Parameters
390 /// * `wake_up` - If `true`, wakes up the parent body (useful when collider removal
391 /// changes the body's mass or collision behavior significantly)
392 ///
393 /// # Example
394 /// ```
395 /// # use rapier3d::prelude::*;
396 /// # let mut colliders = ColliderSet::new();
397 /// # let mut bodies = RigidBodySet::new();
398 /// # let mut islands = IslandManager::new();
399 /// # let body_handle = bodies.insert(RigidBodyBuilder::dynamic().build());
400 /// # let mut soft_bodies = SoftBodySet::new();
401 /// # let handle = colliders.insert_with_parent(ColliderBuilder::ball(0.5).build(), body_handle, &mut bodies);
402 /// if let Some(collider) = colliders.remove(
403 /// handle,
404 /// &mut islands,
405 /// &mut bodies,
406 /// &mut soft_bodies,
407 /// true // Wake up the parent body
408 /// ) {
409 /// println!("Removed collider with shape: {:?}", collider.shared_shape());
410 /// }
411 /// ```
412 pub fn remove(
413 &mut self,
414 handle: ColliderHandle,
415 islands: &mut IslandManager,
416 bodies: &mut RigidBodySet,
417 soft_bodies: &mut SoftBodySet,
418 wake_up: bool,
419 ) -> Option<Collider> {
420 let collider = self.remove_internal(handle, islands, bodies, wake_up)?;
421 // A removed deformable collider takes its mesh with it: the soft body keeps simulating,
422 // without that mesh's collisions.
423 if let Some(mesh) = collider.deformable_mesh_ref() {
424 if let Some(sb) = soft_bodies.get_mut(mesh.body) {
425 sb.remove_mesh(mesh.id);
426 }
427 }
428 Some(collider)
429 }
430
431 /// Like [`Self::remove`], for internal callers that maintain the soft-body back-references
432 /// themselves.
433 pub(crate) fn remove_internal(
434 &mut self,
435 handle: ColliderHandle,
436 islands: &mut IslandManager,
437 bodies: &mut RigidBodySet,
438 wake_up: bool,
439 ) -> Option<Collider> {
440 let collider = self.colliders.remove(handle.0)?;
441
442 /*
443 * Delete the collider from its parent body.
444 */
445 // NOTE: we use `get_mut_internal_with_modification_tracking` instead of `get_mut_internal` so that the
446 // modification flag is updated properly.
447 if let Some(parent) = &collider.parent {
448 if let Some(parent_rb) =
449 bodies.get_mut_internal_with_modification_tracking(parent.handle)
450 {
451 parent_rb.remove_collider_internal(handle);
452
453 if wake_up {
454 islands.wake_up(bodies, parent.handle, true);
455 }
456 }
457 }
458
459 /*
460 * Publish removal.
461 */
462 self.removed_colliders.push(handle);
463
464 Some(collider)
465 }
466
467 /// Gets a collider by its index without knowing the generation number.
468 ///
469 /// ⚠️ **Advanced/unsafe usage** - prefer [`get()`](Self::get) instead! See [`RigidBodySet::get_unknown_gen`] for details.
470 pub fn get_unknown_gen(&self, i: u32) -> Option<(&Collider, ColliderHandle)> {
471 self.colliders
472 .get_unknown_gen(i)
473 .map(|(c, h)| (c, ColliderHandle(h)))
474 }
475
476 /// Gets a mutable reference to a collider by its index without knowing the generation.
477 ///
478 /// ⚠️ **Advanced/unsafe usage** - prefer [`get_mut()`](Self::get_mut) instead!
479 /// suffer form the ABA problem.
480 #[cfg(not(feature = "dev-remove-slow-accessors"))]
481 pub fn get_unknown_gen_mut(&mut self, i: u32) -> Option<(&mut Collider, ColliderHandle)> {
482 let (collider, handle) = self.colliders.get_unknown_gen_mut(i)?;
483 let handle = ColliderHandle(handle);
484 self.modified_colliders.push_once(handle, collider);
485 Some((collider, handle))
486 }
487
488 /// Gets a read-only reference to the collider with the given handle.
489 ///
490 /// Returns `None` if the handle is invalid or the collider was removed.
491 pub fn get(&self, handle: ColliderHandle) -> Option<&Collider> {
492 self.colliders.get(handle.0)
493 }
494
495 /// Gets a mutable reference to the collider with the given handle.
496 ///
497 /// Returns `None` if the handle is invalid or the collider was removed.
498 /// Use this to modify collider properties like friction, restitution, sensor status, etc.
499 #[cfg(not(feature = "dev-remove-slow-accessors"))]
500 pub fn get_mut(&mut self, handle: ColliderHandle) -> Option<&mut Collider> {
501 let result = self.colliders.get_mut(handle.0)?;
502 self.modified_colliders.push_once(handle, result);
503 Some(result)
504 }
505
506 /// Gets mutable references to two different colliders at once.
507 ///
508 /// Useful when you need to modify two colliders simultaneously. If both handles
509 /// are the same, only the first value will be `Some`.
510 #[cfg(not(feature = "dev-remove-slow-accessors"))]
511 pub fn get_pair_mut(
512 &mut self,
513 handle1: ColliderHandle,
514 handle2: ColliderHandle,
515 ) -> (Option<&mut Collider>, Option<&mut Collider>) {
516 if handle1 == handle2 {
517 (self.get_mut(handle1), None)
518 } else {
519 let (mut co1, mut co2) = self.colliders.get2_mut(handle1.0, handle2.0);
520 if let Some(co1) = co1.as_deref_mut() {
521 self.modified_colliders.push_once(handle1, co1);
522 }
523 if let Some(co2) = co2.as_deref_mut() {
524 self.modified_colliders.push_once(handle2, co2);
525 }
526 (co1, co2)
527 }
528 }
529
530 pub(crate) fn index_mut_internal(&mut self, handle: ColliderHandle) -> &mut Collider {
531 &mut self.colliders[handle.0]
532 }
533
534 pub(crate) fn get_mut_internal(&mut self, handle: ColliderHandle) -> Option<&mut Collider> {
535 self.colliders.get_mut(handle.0)
536 }
537
538 // Just a very long name instead of `.get_mut` to make sure
539 // this is really the method we wanted to use instead of `get_mut_internal`.
540 #[allow(dead_code)]
541 pub(crate) fn get_mut_internal_with_modification_tracking(
542 &mut self,
543 handle: ColliderHandle,
544 ) -> Option<&mut Collider> {
545 let result = self.colliders.get_mut(handle.0)?;
546 self.modified_colliders.push_once(handle, result);
547 Some(result)
548 }
549}
550
551impl Index<crate::data::Index> for ColliderSet {
552 type Output = Collider;
553
554 fn index(&self, index: crate::data::Index) -> &Collider {
555 &self.colliders[index]
556 }
557}
558
559impl Index<ColliderHandle> for ColliderSet {
560 type Output = Collider;
561
562 fn index(&self, index: ColliderHandle) -> &Collider {
563 &self.colliders[index.0]
564 }
565}
566
567#[cfg(not(feature = "dev-remove-slow-accessors"))]
568impl IndexMut<ColliderHandle> for ColliderSet {
569 fn index_mut(&mut self, handle: ColliderHandle) -> &mut Collider {
570 let collider = &mut self.colliders[handle.0];
571 self.modified_colliders.push_once(handle, collider);
572 collider
573 }
574}
575
576/// The vertices (world space) and elements of a deformable collider's shape.
577fn mesh_geometry(
578 shape: &dyn crate::geometry::Shape,
579) -> Result<(Vec<Vector>, Vec<[u32; DIM]>), SoftBindingError> {
580 #[cfg(feature = "dim2")]
581 let (deformable, geometry) = {
582 use parry::shape::PolylineFlags;
583 let polyline = shape
584 .as_polyline()
585 .ok_or(SoftBindingError::UnsupportedShape)?;
586 (
587 polyline.flags().contains(PolylineFlags::DEFORMABLE),
588 (polyline.vertices().to_vec(), polyline.indices().to_vec()),
589 )
590 };
591 #[cfg(feature = "dim3")]
592 let (deformable, geometry) = {
593 use parry::shape::TriMeshFlags;
594 let trimesh = shape
595 .as_trimesh()
596 .ok_or(SoftBindingError::UnsupportedShape)?;
597 (
598 trimesh.flags().contains(TriMeshFlags::DEFORMABLE),
599 (trimesh.vertices().to_vec(), trimesh.indices().to_vec()),
600 )
601 };
602 if !deformable {
603 return Err(SoftBindingError::NotDeformable);
604 }
605 let (vertices, indices) = geometry;
606 if vertices.is_empty() || indices.is_empty() {
607 return Err(SoftBindingError::DegenerateMesh);
608 }
609 Ok((vertices, indices))
610}