diff --git a/src/dynamics/rigid_body.rs b/src/dynamics/rigid_body.rs index 492e7c00..a6c30492 100644 --- a/src/dynamics/rigid_body.rs +++ b/src/dynamics/rigid_body.rs @@ -566,6 +566,16 @@ pub struct TransformInterpolation { } impl TransformInterpolation { + /// Skips interpolation, effectively causing the body to immediately teleport to its current + /// transform. + /// + /// This is most useful with kinematic character controllers, which always interpolate and do + /// not perform transform change detection like rigid bodies do. + pub fn teleport(&mut self) { + self.start = None; + self.end = None; + } + /// Interpolates between the start and end positions with `t` in the range `[0..1]`. pub fn lerp_slerp(&self, t: f32) -> Option> { if let (Some(start), Some(end)) = (self.start, self.end) { diff --git a/src/plugin/context.rs b/src/plugin/context.rs index 016609c2..41e1a2a9 100644 --- a/src/plugin/context.rs +++ b/src/plugin/context.rs @@ -249,8 +249,8 @@ impl RapierContext { // Update the previous state transforms for (handle, mut interpolation) in interpolation_query.iter_mut() { if let Some(body) = self.bodies.get(handle.0) { - interpolation.start = Some(*body.position()); - interpolation.end = None; + interpolation.start = interpolation.end; + interpolation.end = Some(*body.position()); } } } diff --git a/src/plugin/systems.rs b/src/plugin/systems.rs index 7deb595e..8ddf6060 100644 --- a/src/plugin/systems.rs +++ b/src/plugin/systems.rs @@ -280,6 +280,7 @@ pub fn apply_rigid_body_user_changes( &RapierRigidBodyHandle, &GlobalTransform, Option<&mut TransformInterpolation>, + Option<&KinematicCharacterController>, ), Changed, >, @@ -354,24 +355,30 @@ pub fn apply_rigid_body_user_changes( } }; - for (handle, global_transform, mut interpolation) in changed_transforms.iter_mut() { + for (handle, global_transform, mut interpolation, kinematic_character_controller) in + changed_transforms.iter_mut() + { // Use an Option to avoid running the check twice. let mut transform_changed = None; - if let Some(interpolation) = interpolation.as_deref_mut() { - transform_changed = transform_changed.or_else(|| { - Some(transform_changed_fn( - &handle.0, - global_transform, - &context.last_body_transform_set, - )) - }); - - if transform_changed == Some(true) { - // Reset the interpolation so we don’t overwrite - // the user’s input. - interpolation.start = None; - interpolation.end = None; + // Kinematic character controllers update outside of our tick loop, and therefore we must + // exclude them from interpolation. + if kinematic_character_controller.is_none() { + if let Some(interpolation) = interpolation.as_deref_mut() { + transform_changed = transform_changed.or_else(|| { + Some(transform_changed_fn( + &handle.0, + global_transform, + &context.last_body_transform_set, + )) + }); + + if transform_changed == Some(true) { + // Reset the interpolation so we don’t overwrite + // the user’s input. + interpolation.start = None; + interpolation.end = None; + } } }