bevy_rapier3d/control/
controller_filter.rs1use bevy::ecs::entity::EntityHashSet;
2use bevy::prelude::{Component, Entity, Reflect, ReflectComponent, ReflectDefault};
3use rapier::dynamics::RigidBodyHandle;
4use rapier::geometry::Collider as RapierCollider;
5use std::fmt;
6use std::sync::Arc;
7
8use crate::plugin::context::{RapierContextColliders, RapierRigidBodySet};
9
10#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Component, Reflect)]
19#[reflect(Component, Default, PartialEq)]
20pub struct ControllerIgnored;
21
22#[derive(Clone)]
29#[allow(clippy::type_complexity)]
30pub struct ControllerFilterPredicate(
31 pub Arc<dyn Fn(Entity, &RapierCollider) -> bool + Send + Sync>,
32);
33
34impl ControllerFilterPredicate {
35 pub fn new(
37 predicate: impl Fn(Entity, &RapierCollider) -> bool + Send + Sync + 'static,
38 ) -> Self {
39 Self(Arc::new(predicate))
40 }
41
42 pub fn test(&self, entity: Entity, collider: &RapierCollider) -> bool {
44 (self.0)(entity, collider)
45 }
46}
47
48impl fmt::Debug for ControllerFilterPredicate {
49 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
50 f.write_str("ControllerFilterPredicate(..)")
51 }
52}
53
54pub(crate) struct ControllerExclusions<'a> {
56 colliders: &'a EntityHashSet,
57 ignored: &'a EntityHashSet,
59 rigid_bodies: Vec<RigidBodyHandle>,
60 predicate: Option<&'a ControllerFilterPredicate>,
61}
62
63impl<'a> ControllerExclusions<'a> {
64 pub fn new(
67 colliders: &'a EntityHashSet,
68 rigid_bodies: &EntityHashSet,
69 ignored: &'a EntityHashSet,
70 predicate: Option<&'a ControllerFilterPredicate>,
71 rigidbody_set: &RapierRigidBodySet,
72 ) -> Self {
73 let rigid_bodies = rigid_bodies
74 .iter()
75 .chain(ignored.iter())
76 .filter_map(|e| rigidbody_set.entity2body.get(e).copied())
77 .collect();
78 Self {
79 colliders,
80 ignored,
81 rigid_bodies,
82 predicate,
83 }
84 }
85
86 pub fn is_empty(&self) -> bool {
88 self.colliders.is_empty()
89 && self.ignored.is_empty()
90 && self.rigid_bodies.is_empty()
91 && self.predicate.is_none()
92 }
93
94 pub fn test(&self, collider: &RapierCollider) -> bool {
96 let entity = RapierContextColliders::entity_from_collider(collider);
97 !self.colliders.contains(&entity)
98 && !self.ignored.contains(&entity)
99 && collider
100 .parent()
101 .is_none_or(|parent| !self.rigid_bodies.contains(&parent))
102 && self.predicate.is_none_or(|p| p.test(entity, collider))
103 }
104}