bevy_rapier3d/plugin/systems/
joint.rs1use crate::dynamics::ImpulseJoint;
2use crate::dynamics::MultibodyJoint;
3use crate::dynamics::RapierImpulseJointHandle;
4use crate::dynamics::RapierMultibodyJointHandle;
5use crate::plugin::context::systemparams::RAPIER_CONTEXT_EXPECT_ERROR;
6use crate::plugin::context::DefaultRapierContext;
7use crate::plugin::context::RapierContextEntityLink;
8use crate::plugin::context::RapierContextJoints;
9use crate::plugin::context::RapierRigidBodySet;
10use bevy::prelude::*;
11
12pub fn init_joints(
14 mut commands: Commands,
15 mut context_access: Query<(&RapierRigidBodySet, &mut RapierContextJoints)>,
16 default_context_access: Query<Entity, With<DefaultRapierContext>>,
17 impulse_joints: Query<
18 (Entity, Option<&RapierContextEntityLink>, &ImpulseJoint),
19 Without<RapierImpulseJointHandle>,
20 >,
21 multibody_joints: Query<
22 (Entity, Option<&RapierContextEntityLink>, &MultibodyJoint),
23 Without<RapierMultibodyJointHandle>,
24 >,
25 child_of_query: Query<&ChildOf>,
26) {
27 for (entity, entity_context_link, joint) in impulse_joints.iter() {
28 let context_entity = entity_context_link.map_or_else(
30 || {
31 let context_entity = default_context_access.single().ok()?;
32 commands
33 .entity(entity)
34 .insert(RapierContextEntityLink(context_entity));
35 Some(context_entity)
36 },
37 |link| Some(link.0),
38 );
39 let Some(context_entity) = context_entity else {
40 continue;
41 };
42
43 let Ok(rigidbody_set_joints) = context_access.get_mut(context_entity) else {
44 log::error!("Could not find entity {context_entity} with rapier context while initializing {entity}");
45 continue;
46 };
47 let rigidbody_set = rigidbody_set_joints.0;
48 let mut target = None;
49 let mut body_entity = entity;
50 while target.is_none() {
51 target = rigidbody_set.entity2body.get(&body_entity).copied();
52 if let Ok(child_of) = child_of_query.get(body_entity) {
53 body_entity = child_of.parent();
54 } else {
55 break;
56 }
57 }
58 let joints = rigidbody_set_joints.1.into_inner();
59
60 if let (Some(target), Some(source)) = (target, rigidbody_set.entity2body.get(&joint.parent))
61 {
62 let handle = joints.impulse_joints.insert(
63 *source,
64 target,
65 joint.data.as_ref().into_rapier(),
66 true,
67 );
68 commands
69 .entity(entity)
70 .insert(RapierImpulseJointHandle(handle));
71 joints.entity2impulse_joint.insert(entity, handle);
72 }
73 }
74
75 for (entity, entity_context_link, joint) in multibody_joints.iter() {
76 let context_entity = entity_context_link.map_or_else(
78 || {
79 let context_entity = default_context_access.single().ok()?;
80 commands
81 .entity(entity)
82 .insert(RapierContextEntityLink(context_entity));
83 Some(context_entity)
84 },
85 |link| Some(link.0),
86 );
87 let Some(context_entity) = context_entity else {
88 continue;
89 };
90
91 let Ok(context_joints) = context_access.get_mut(context_entity) else {
92 log::error!("Could not find entity {context_entity} with rapier context while initializing {entity}");
93 continue;
94 };
95 let context = context_joints.0;
96 let target = context.entity2body.get(&entity);
97 let joints = context_joints.1.into_inner();
98
99 if let (Some(target), Some(source)) = (target, context.entity2body.get(&joint.parent)) {
100 if let Some(handle) = joints.multibody_joints.insert(
101 *source,
102 *target,
103 joint.data.as_ref().into_rapier(),
104 true,
105 ) {
106 commands
107 .entity(entity)
108 .insert(RapierMultibodyJointHandle(handle));
109 joints.entity2multibody_joint.insert(entity, handle);
110 } else {
111 log::error!("Failed to create multibody joint: loop detected.")
112 }
113 }
114 }
115}
116
117pub fn apply_joint_user_changes(
119 mut context: Query<&mut RapierContextJoints>,
120 changed_impulse_joints: Query<
121 (
122 &RapierContextEntityLink,
123 &RapierImpulseJointHandle,
124 &ImpulseJoint,
125 ),
126 Changed<ImpulseJoint>,
127 >,
128 changed_multibody_joints: Query<
129 (
130 &RapierContextEntityLink,
131 &RapierMultibodyJointHandle,
132 &MultibodyJoint,
133 ),
134 Changed<MultibodyJoint>,
135 >,
136) {
137 for (link, handle, changed_joint) in changed_impulse_joints.iter() {
140 let mut context = context.get_mut(link.0).expect(RAPIER_CONTEXT_EXPECT_ERROR);
141 if let Some(joint) = context.impulse_joints.get_mut(handle.0, false) {
142 joint.data = changed_joint.data.as_ref().into_rapier();
143 }
144 }
145
146 for (link, handle, changed_joint) in changed_multibody_joints.iter() {
147 let mut context = context.get_mut(link.0).expect(RAPIER_CONTEXT_EXPECT_ERROR);
148 if let Some((mb, link_id)) = context.multibody_joints.get_mut(handle.0) {
150 if let Some(link) = mb.link_mut(link_id) {
151 link.joint.data = changed_joint.data.as_ref().into_rapier();
152 }
153 }
154 }
155}