bevy_rapier3d/plugin/systems/
remove.rs

1use crate::dynamics::ImpulseJoint;
2use crate::dynamics::MultibodyJoint;
3use crate::dynamics::RapierImpulseJointHandle;
4use crate::dynamics::RapierMultibodyJointHandle;
5use crate::dynamics::RapierRigidBodyHandle;
6use crate::dynamics::RigidBody;
7use crate::geometry::Collider;
8use crate::geometry::ColliderDisabled;
9use crate::geometry::RapierColliderHandle;
10use crate::plugin::context::{
11    RapierContextColliders, RapierContextJoints, RapierContextSimulation, RapierRigidBodySet,
12};
13use crate::prelude::MassModifiedEvent;
14use crate::prelude::RigidBodyDisabled;
15use crate::prelude::Sensor;
16use bevy::ecs::query::QueryData;
17use bevy::prelude::*;
18
19/// System responsible for removing from Rapier the rigid-bodies/colliders/joints which had
20/// their related `bevy_rapier` components removed by the user (through component removal or
21/// despawn).
22pub fn sync_removals(
23    mut commands: Commands,
24    mut context_writer: Query<(
25        &mut RapierContextSimulation,
26        &mut RapierContextColliders,
27        &mut RapierContextJoints,
28        &mut RapierRigidBodySet,
29    )>,
30    mut removed_bodies: RemovedComponents<RapierRigidBodyHandle>,
31    mut removed_colliders: RemovedComponents<RapierColliderHandle>,
32    mut removed_impulse_joints: RemovedComponents<RapierImpulseJointHandle>,
33    mut removed_multibody_joints: RemovedComponents<RapierMultibodyJointHandle>,
34    orphan_bodies: Query<Entity, (With<RapierRigidBodyHandle>, Without<RigidBody>)>,
35    orphan_colliders: Query<Entity, (With<RapierColliderHandle>, Without<Collider>)>,
36    orphan_impulse_joints: Query<Entity, (With<RapierImpulseJointHandle>, Without<ImpulseJoint>)>,
37    orphan_multibody_joints: Query<
38        Entity,
39        (With<RapierMultibodyJointHandle>, Without<MultibodyJoint>),
40    >,
41
42    mut removed_sensors: RemovedComponents<Sensor>,
43    mut removed_rigid_body_disabled: RemovedComponents<RigidBodyDisabled>,
44    mut removed_colliders_disabled: RemovedComponents<ColliderDisabled>,
45
46    mut mass_modified: MessageWriter<MassModifiedEvent>,
47) {
48    /*
49     * Rigid-bodies removal detection.
50     */
51    for entity in removed_bodies.read() {
52        let Some(((mut context, mut context_colliders, mut joints, mut rigidbody_set), handle)) =
53            find_context(&mut context_writer, |res| res.3.entity2body.remove(&entity))
54        else {
55            continue;
56        };
57        let context = &mut *context;
58        let joints = &mut *joints;
59
60        let _ = rigidbody_set.last_body_transform_set.remove(&handle);
61        rigidbody_set.bodies.remove(
62            handle,
63            &mut context.islands,
64            &mut context_colliders.colliders,
65            &mut joints.impulse_joints,
66            &mut joints.multibody_joints,
67            false,
68        );
69    }
70
71    for entity in orphan_bodies.iter() {
72        if let Some(((mut context, mut context_colliders, mut joints, mut rigidbody_set), handle)) =
73            find_context(&mut context_writer, |res| res.3.entity2body.remove(&entity))
74        {
75            let context = &mut *context;
76            let joints = &mut *joints;
77            let _ = rigidbody_set.last_body_transform_set.remove(&handle);
78            rigidbody_set.bodies.remove(
79                handle,
80                &mut context.islands,
81                &mut context_colliders.colliders,
82                &mut joints.impulse_joints,
83                &mut joints.multibody_joints,
84                false,
85            );
86        }
87        commands.entity(entity).remove::<RapierRigidBodyHandle>();
88    }
89
90    /*
91     * Collider removal detection.
92     */
93    for entity in removed_colliders.read() {
94        let Some(((mut context, mut context_colliders, _, mut rigidbody_set), handle)) =
95            find_context(&mut context_writer, |res| {
96                res.1.entity2collider.remove(&entity)
97            })
98        else {
99            continue;
100        };
101        let context = &mut *context;
102        if let Some(parent) = context_colliders.collider_parent(&rigidbody_set, entity) {
103            mass_modified.write(parent.into());
104        }
105
106        context_colliders.colliders.remove(
107            handle,
108            &mut context.islands,
109            &mut rigidbody_set.bodies,
110            true,
111        );
112        context.deleted_colliders.insert(handle, entity);
113    }
114
115    for entity in orphan_colliders.iter() {
116        if let Some(((mut context, mut context_colliders, _, mut rigidbody_set), handle)) =
117            find_context(&mut context_writer, |res| {
118                res.1.entity2collider.remove(&entity)
119            })
120        {
121            let context = &mut *context;
122            let context_colliders = &mut *context_colliders;
123            if let Some(parent) = context_colliders.collider_parent(&rigidbody_set, entity) {
124                mass_modified.write(parent.into());
125            }
126
127            context_colliders.colliders.remove(
128                handle,
129                &mut context.islands,
130                &mut rigidbody_set.bodies,
131                true,
132            );
133            context.deleted_colliders.insert(handle, entity);
134        }
135        commands.entity(entity).remove::<RapierColliderHandle>();
136    }
137
138    /*
139     * Impulse joint removal detection.
140     */
141    for entity in removed_impulse_joints.read() {
142        let Some(((_, _, mut joints, _), handle)) = find_context(&mut context_writer, |res| {
143            res.2.entity2impulse_joint.remove(&entity)
144        }) else {
145            continue;
146        };
147        joints.impulse_joints.remove(handle, true);
148    }
149
150    for entity in orphan_impulse_joints.iter() {
151        if let Some(((_, _, mut joints, _), handle)) = find_context(&mut context_writer, |res| {
152            res.2.entity2impulse_joint.remove(&entity)
153        }) {
154            joints.impulse_joints.remove(handle, true);
155        }
156        commands.entity(entity).remove::<RapierImpulseJointHandle>();
157    }
158
159    /*
160     * Multibody joint removal detection.
161     */
162    for entity in removed_multibody_joints.read() {
163        let Some(((_, _, mut joints, _), handle)) = find_context(&mut context_writer, |res| {
164            res.2.entity2multibody_joint.remove(&entity)
165        }) else {
166            continue;
167        };
168        joints.multibody_joints.remove(handle, true);
169    }
170
171    for entity in orphan_multibody_joints.iter() {
172        if let Some(((_, _, mut joints, _), handle)) = find_context(&mut context_writer, |res| {
173            res.2.entity2multibody_joint.remove(&entity)
174        }) {
175            joints.multibody_joints.remove(handle, true);
176        }
177        commands
178            .entity(entity)
179            .remove::<RapierMultibodyJointHandle>();
180    }
181
182    /*
183     * Marker components removal detection.
184     */
185    for entity in removed_sensors.read() {
186        if let Some((mut context, handle)) = find_context(&mut context_writer, |context| {
187            context.1.entity2collider.get(&entity).copied()
188        }) {
189            if let Some(co) = context.1.colliders.get_mut(handle) {
190                co.set_sensor(false);
191            }
192        }
193    }
194
195    for entity in removed_colliders_disabled.read() {
196        if let Some((mut context, handle)) = find_context(&mut context_writer, |context| {
197            context.1.entity2collider.get(&entity).copied()
198        }) {
199            if let Some(co) = context.1.colliders.get_mut(handle) {
200                co.set_enabled(true);
201            }
202        }
203    }
204
205    for entity in removed_rigid_body_disabled.read() {
206        if let Some(((_, _, _, mut rigidbody_set), handle)) =
207            find_context(&mut context_writer, |res| {
208                res.3.entity2body.get(&entity).copied()
209            })
210        {
211            if let Some(rb) = rigidbody_set.bodies.get_mut(handle) {
212                rb.set_enabled(true);
213            }
214        }
215    }
216
217    // TODO: what about removing forces?
218}
219
220fn find_context<'a, TReturn, TQueryParams: QueryData>(
221    context_writer: &'a mut Query<TQueryParams>,
222    item_finder: impl Fn(&mut TQueryParams::Item<'_, '_>) -> Option<TReturn>,
223) -> Option<(TQueryParams::Item<'a, 'a>, TReturn)> {
224    let ret: Option<(TQueryParams::Item<'_, '_>, TReturn)> = context_writer
225        .iter_mut()
226        .find_map(|mut context| item_finder(&mut context).map(|handle| (context, handle)));
227    ret
228}