1use crate::{
26 core::{
27 algebra::{Matrix4, UnitQuaternion, Vector3},
28 log::Log,
29 math::{aabb::AxisAlignedBoundingBox, Matrix4Ext},
30 pool::{Handle, PoolError},
31 reflect::prelude::*,
32 type_traits::prelude::*,
33 uuid::{uuid, Uuid},
34 uuid_provider,
35 variable::InheritableVariable,
36 visitor::prelude::*,
37 },
38 graph::SceneGraph,
39 scene::{
40 base::{Base, BaseBuilder},
41 collider::Collider,
42 graph::Graph,
43 node::{constructor::NodeConstructor, Node, NodeTrait, UpdateContext},
44 rigidbody::{RigidBody, RigidBodyType},
45 },
46};
47use fyrox_graph::constructor::ConstructorProvider;
48use std::ops::{Deref, DerefMut};
49
50#[derive(Clone, Debug, PartialEq, Default, Visit, Reflect)]
53pub struct Limb {
54 pub bone: Handle<Node>,
56 pub physical_bone: Handle<RigidBody>,
58 pub children: Vec<Limb>,
60}
61
62uuid_provider!(Limb = "6d5bc2f7-8acc-4b64-8e4b-65d4551150bf");
63
64impl Limb {
65 pub fn iterate_recursive<F>(&self, func: &mut F) -> Result<(), PoolError>
68 where
69 F: FnMut(&Self) -> Result<(), PoolError>,
70 {
71 func(self)?;
72
73 for child in self.children.iter() {
74 child.iterate_recursive(func)?
75 }
76
77 Ok(())
78 }
79}
80
81#[derive(Clone, Reflect, Visit, Debug, Default, ComponentProvider)]
92#[reflect(derived_type = "Node")]
93#[visit(optional)]
94pub struct Ragdoll {
95 base: Base,
96 pub character_rigid_body: InheritableVariable<Handle<RigidBody>>,
99 pub is_active: InheritableVariable<bool>,
102 pub root_limb: InheritableVariable<Limb>,
105 pub deactivate_colliders: InheritableVariable<bool>,
108 #[reflect(hidden)]
109 prev_enabled: bool,
110}
111
112impl Deref for Ragdoll {
113 type Target = Base;
114
115 fn deref(&self) -> &Self::Target {
116 &self.base
117 }
118}
119
120impl DerefMut for Ragdoll {
121 fn deref_mut(&mut self) -> &mut Self::Target {
122 &mut self.base
123 }
124}
125
126impl TypeUuidProvider for Ragdoll {
127 fn type_uuid() -> Uuid {
128 uuid!("f4441683-dcef-472d-9d7d-4adca4579107")
129 }
130}
131
132impl ConstructorProvider<Node, Graph> for Ragdoll {
133 fn constructor() -> NodeConstructor {
134 NodeConstructor::new::<Self>()
135 .with_variant("Ragdoll", |_| {
136 RagdollBuilder::new(BaseBuilder::new().with_name("Ragdoll"))
137 .build_node()
138 .into()
139 })
140 .with_group("Physics")
141 }
142}
143
144impl NodeTrait for Ragdoll {
145 fn local_bounding_box(&self) -> AxisAlignedBoundingBox {
146 self.base.local_bounding_box()
147 }
148
149 fn world_bounding_box(&self) -> AxisAlignedBoundingBox {
150 self.base.world_bounding_box()
151 }
152
153 fn id(&self) -> Uuid {
154 Self::type_uuid()
155 }
156
157 fn update(&mut self, ctx: &mut UpdateContext) {
158 let mut new_lin_vel = None;
160 let mut new_ang_vel = None;
161 if *self.is_active && !self.prev_enabled {
162 if let Ok(character_rigid_body) = ctx.nodes.try_get(*self.character_rigid_body) {
163 new_lin_vel = Some(character_rigid_body.lin_vel());
164 new_ang_vel = Some(character_rigid_body.ang_vel());
165 }
166 }
167 self.prev_enabled = *self.is_active;
168
169 Log::verify(self.root_limb.iterate_recursive(&mut |limb| {
170 let mbc = ctx.nodes.begin_multi_borrow();
171
172 let mut need_update_transform = false;
173
174 let mut limb_body = mbc.try_get_mut(limb.physical_bone)?;
175 if *self.is_active {
176 if let Some(lin_vel) = new_lin_vel {
178 limb_body.set_lin_vel(lin_vel);
179 }
180 if let Some(ang_vel) = new_ang_vel {
181 limb_body.set_ang_vel(ang_vel);
182 }
183
184 if limb_body.body_type() != RigidBodyType::Dynamic {
185 limb_body.set_body_type(RigidBodyType::Dynamic);
186 }
187
188 if *self.deactivate_colliders {
189 for child in limb_body.children() {
190 if let Ok(mut collider) =
191 mbc.try_get_component_of_type_mut::<Collider>(*child)
192 {
193 collider.set_is_sensor(false);
194 }
195 }
196 }
197
198 let body_transform = limb_body.global_transform();
199
200 let bone_parent = mbc.try_get(limb.bone)?.parent();
202 let transform: Matrix4<f32> = mbc
203 .try_get(bone_parent)?
204 .global_transform()
205 .try_inverse()
206 .unwrap_or_else(Matrix4::identity)
207 * body_transform;
208
209 mbc.try_get_mut(limb.bone)?
210 .local_transform_mut()
211 .set_position(Vector3::new(transform[12], transform[13], transform[14]))
212 .set_pre_rotation(UnitQuaternion::identity())
213 .set_post_rotation(UnitQuaternion::identity())
214 .set_rotation(UnitQuaternion::from_matrix_eps(
215 &transform.basis(),
216 f32::EPSILON,
217 16,
218 Default::default(),
219 ));
220
221 need_update_transform = true;
222 } else {
223 limb_body.set_body_type(RigidBodyType::KinematicPositionBased);
224 limb_body.set_lin_vel(Default::default());
225 limb_body.set_ang_vel(Default::default());
226
227 if *self.deactivate_colliders {
228 for child in limb_body.children() {
229 if let Ok(mut collider) =
230 mbc.try_get_component_of_type_mut::<Collider>(*child)
231 {
232 collider.set_is_sensor(true);
233 }
234 }
235 }
236
237 let self_transform_inverse =
238 self.global_transform().try_inverse().unwrap_or_default();
239
240 let bone = mbc.try_get(limb.bone)?;
242 let relative_transform = self_transform_inverse * bone.global_transform();
243
244 let position = Vector3::new(
245 relative_transform[12],
246 relative_transform[13],
247 relative_transform[14],
248 );
249 let rotation = UnitQuaternion::from_matrix_eps(
250 &relative_transform.basis(),
251 f32::EPSILON,
252 16,
253 Default::default(),
254 );
255 limb_body
256 .local_transform_mut()
257 .set_position(position)
258 .set_rotation(rotation);
259 }
260
261 drop(limb_body);
262 drop(mbc);
263
264 if need_update_transform {
265 Graph::update_hierarchical_data_recursively(
268 ctx.nodes,
269 ctx.sound_context,
270 ctx.physics,
271 ctx.physics2d,
272 limb.bone,
273 );
274 }
275
276 Ok(())
277 }));
278
279 if let Ok(root_limb_body) = ctx.nodes.try_borrow(self.root_limb.bone) {
280 let position = root_limb_body.global_position();
281 if let Ok(character_rigid_body) = ctx.nodes.try_get_mut(*self.character_rigid_body) {
282 if *self.is_active {
283 character_rigid_body.set_lin_vel(Default::default());
284 character_rigid_body.set_ang_vel(Default::default());
285 character_rigid_body
286 .local_transform_mut()
287 .set_position(position);
288 character_rigid_body.set_body_type(RigidBodyType::KinematicPositionBased);
289 } else {
290 character_rigid_body.set_body_type(RigidBodyType::Dynamic);
291 }
292 }
293 }
294 }
295}
296
297pub struct RagdollBuilder {
299 base_builder: BaseBuilder,
300 character_rigid_body: Handle<RigidBody>,
301 is_active: bool,
302 deactivate_colliders: bool,
303 root_limb: Limb,
304}
305
306impl RagdollBuilder {
307 pub fn new(base_builder: BaseBuilder) -> Self {
309 Self {
310 base_builder,
311 character_rigid_body: Default::default(),
312 is_active: true,
313 deactivate_colliders: false,
314 root_limb: Default::default(),
315 }
316 }
317
318 pub fn with_character_rigid_body(mut self, handle: Handle<RigidBody>) -> Self {
320 self.character_rigid_body = handle;
321 self
322 }
323
324 pub fn with_active(mut self, active: bool) -> Self {
326 self.is_active = active;
327 self
328 }
329
330 pub fn with_root_limb(mut self, root_limb: Limb) -> Self {
332 self.root_limb = root_limb;
333 self
334 }
335
336 pub fn with_deactivate_colliders(mut self, value: bool) -> Self {
338 self.deactivate_colliders = value;
339 self
340 }
341
342 pub fn build_ragdoll(self) -> Ragdoll {
344 Ragdoll {
345 base: self.base_builder.build_base(),
346 character_rigid_body: self.character_rigid_body.into(),
347 is_active: self.is_active.into(),
348 root_limb: self.root_limb.into(),
349 deactivate_colliders: self.deactivate_colliders.into(),
350 prev_enabled: self.is_active,
351 }
352 }
353
354 pub fn build_node(self) -> Node {
356 Node::new(self.build_ragdoll())
357 }
358
359 pub fn build(self, graph: &mut Graph) -> Handle<Ragdoll> {
361 graph.add_node(self.build_node()).to_variant()
362 }
363}