Skip to main content

bevy_rapier3d/plugin/systems/
writeback.rs

1use crate::dynamics::MassProperties;
2use crate::dynamics::ReadMassProperties;
3use crate::geometry::{
4    Collider, ColliderMassProperties, RapierColliderHandle, ReadColliderMassProperties,
5};
6use crate::plugin::context::{RapierContextColliders, RapierContextEntityLink, RapierRigidBodySet};
7use crate::plugin::RapierConfiguration;
8use crate::prelude::MassModifiedEvent;
9use bevy::prelude::*;
10
11/// System responsible for writing updated mass properties back into the [`ReadMassProperties`] component.
12pub fn writeback_mass_properties(
13    link: Query<&RapierContextEntityLink>,
14    rigidbody_set: Query<&RapierRigidBodySet>,
15    config: Query<&RapierConfiguration>,
16
17    mut mass_props: Query<&mut ReadMassProperties>,
18    mut mass_modified: MessageReader<MassModifiedEvent>,
19) {
20    for entity in mass_modified.read() {
21        let link = link
22            .get(entity.0)
23            .expect("Could not find `RapierContextEntityLink`");
24        let config = config
25            .get(link.0)
26            .expect("Could not find `RapierConfiguration`");
27        if config.physics_pipeline_active {
28            let Ok(rigidbody_set) = rigidbody_set.get(link.0) else {
29                continue;
30            };
31
32            if let Some(handle) = rigidbody_set.entity2body.get(entity).copied() {
33                if let Some(rb) = rigidbody_set.bodies.get(handle) {
34                    if let Ok(mut mass_props) = mass_props.get_mut(**entity) {
35                        let new_mass_props =
36                            MassProperties::from_rapier(rb.mass_properties().local_mprops);
37
38                        // NOTE: we write the new value only if there was an
39                        //       actual change, in order to not trigger bevy’s
40                        //       change tracking when the values didn’t change.
41                        if mass_props.get() != &new_mass_props {
42                            mass_props.set(new_mass_props);
43                        }
44                    }
45                }
46            }
47        }
48    }
49}
50
51/// System responsible for writing the mass properties of colliders back into the
52/// [`ReadColliderMassProperties`] component.
53///
54/// This runs for colliders that were just created, or with a modified shape or
55/// [`ColliderMassProperties`].
56pub fn writeback_collider_mass_properties(
57    context_colliders: Query<&RapierContextColliders>,
58    mut colliders: Query<
59        (
60            &RapierColliderHandle,
61            &RapierContextEntityLink,
62            &mut ReadColliderMassProperties,
63        ),
64        Or<(
65            Added<RapierColliderHandle>,
66            Added<ReadColliderMassProperties>,
67            Changed<Collider>,
68            Changed<ColliderMassProperties>,
69        )>,
70    >,
71) {
72    for (handle, link, mut mass_props) in colliders.iter_mut() {
73        let Some(co) = context_colliders
74            .get(link.0)
75            .ok()
76            .and_then(|ctxt| ctxt.colliders.get(handle.0))
77        else {
78            continue;
79        };
80
81        // NOTE: only write actual changes to avoid triggering bevy's change detection.
82        mass_props.set_if_neq(ReadColliderMassProperties::from_rapier(co));
83    }
84}