From d49f79873a6ad3589cd9d489ae81622ca6964cf1 Mon Sep 17 00:00:00 2001 From: Hennadii Chernyshchyk Date: Fri, 25 Oct 2024 03:03:42 +0300 Subject: [PATCH] Fix `SmoothDelta` modifier --- CHANGELOG.md | 4 + .../input_modifier/smooth_delta.rs | 117 +++++------------- 2 files changed, 32 insertions(+), 89 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bf1f542..a195d23 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Logging for binding. +### Fixed + +- `SmoothDelta` modifier. + ### Changed - Remove world access from conditions and modifiers. This means that you no longer can write game-specific conditions or modifiers. But it's much nicer (and faster) to just do it in observers instead. diff --git a/src/input_context/input_modifier/smooth_delta.rs b/src/input_context/input_modifier/smooth_delta.rs index 8f71587..cd223a5 100644 --- a/src/input_context/input_modifier/smooth_delta.rs +++ b/src/input_context/input_modifier/smooth_delta.rs @@ -18,9 +18,7 @@ pub struct SmoothDelta { /// Multiplier for delta time. pub speed: f32, - old_value: Vec3, - - value_delta: Vec3, + prev_value: Vec3, } impl SmoothDelta { @@ -29,8 +27,7 @@ impl SmoothDelta { Self { kind: kind.into(), speed, - old_value: Default::default(), - value_delta: Default::default(), + prev_value: Default::default(), } } } @@ -42,21 +39,24 @@ impl InputModifier for SmoothDelta { return self.apply(time, value.into()); } - let dim = value.dim(); - let value = value.as_axis3d(); - let target_value_delta = (value - self.old_value).normalize_or_zero(); - self.old_value = value; + let target_value = value.as_axis3d(); + if self.prev_value.distance_squared(target_value) < 1e-4 { + // Snap to the target if the distance is too small. + self.prev_value = target_value; + return value; + } - let alpha = (time.delta_seconds() * self.speed).min(1.0); - self.value_delta = match self.kind { + let alpha = time.delta_seconds() * self.speed; + let smoothed = match self.kind { SmoothKind::EaseFunction(ease_function) => { let ease_alpha = alpha.calc(ease_function); - self.value_delta.lerp(target_value_delta, ease_alpha) + self.prev_value.lerp(target_value, ease_alpha) } - SmoothKind::Linear => self.value_delta.lerp(target_value_delta, alpha), + SmoothKind::Linear => self.prev_value.lerp(target_value, alpha), }; + self.prev_value = smoothed; - ActionValue::Axis3D(self.value_delta).convert(dim) + ActionValue::Axis3D(smoothed).convert(value.dim()) } } @@ -84,106 +84,45 @@ mod tests { use super::*; #[test] - fn linear_bool() { - let mut modifier = SmoothDelta::new(SmoothKind::Linear, 1.0); - let mut time = Time::default(); - time.advance_by(Duration::from_millis(100)); - - assert_eq!(modifier.apply(&time, false.into()), 0.0.into()); - assert_eq!(modifier.apply(&time, true.into()), 0.1.into()); - } - - #[test] - fn ease_function_bool() { - let mut modifier = SmoothDelta::new(EaseFunction::QuadraticIn, 1.0); - let mut time = Time::default(); - time.advance_by(Duration::from_millis(200)); - - assert_eq!(modifier.apply(&time, false.into()), 0.0.into()); - assert_eq!(modifier.apply(&time, true.into()), 0.040000003.into()); - } - - #[test] - fn linear_axis1d() { + fn linear() { let mut modifier = SmoothDelta::new(SmoothKind::Linear, 1.0); let mut time = Time::default(); time.advance_by(Duration::from_millis(100)); - assert_eq!(modifier.apply(&time, 0.5.into()), 0.1.into()); - assert_eq!(modifier.apply(&time, 1.0.into()), 0.19.into()); + assert_eq!(modifier.apply(&time, 0.5.into()), 0.05.into()); + assert_eq!(modifier.apply(&time, 1.0.into()), 0.145.into()); } #[test] - fn ease_function_axis1d() { + fn ease_function() { let mut modifier = SmoothDelta::new(EaseFunction::QuadraticIn, 1.0); let mut time = Time::default(); time.advance_by(Duration::from_millis(200)); - assert_eq!(modifier.apply(&time, 0.5.into()), 0.040000003.into()); - assert_eq!(modifier.apply(&time, 1.0.into()), 0.0784.into()); + assert_eq!(modifier.apply(&time, 0.5.into()), 0.020000001.into()); + assert_eq!(modifier.apply(&time, 1.0.into()), 0.059200004.into()); } #[test] - fn linear_axis2d() { + fn bool_as_axis1d() { let mut modifier = SmoothDelta::new(SmoothKind::Linear, 1.0); let mut time = Time::default(); time.advance_by(Duration::from_millis(100)); - assert_eq!( - modifier.apply(&time, Vec2::splat(0.5).into()), - Vec2::splat(0.07071068).into() - ); - assert_eq!( - modifier.apply(&time, Vec2::ONE.into()), - Vec2::splat(0.1343503).into() - ); - } - - #[test] - fn ease_function_axis2d() { - let mut modifier = SmoothDelta::new(EaseFunction::QuadraticIn, 1.0); - let mut time = Time::default(); - time.advance_by(Duration::from_millis(200)); - - assert_eq!( - modifier.apply(&time, Vec2::splat(0.5).into()), - Vec2::splat(0.028284272).into() - ); - assert_eq!( - modifier.apply(&time, Vec2::ONE.into()), - Vec2::splat(0.055437177).into() - ); + assert_eq!(modifier.apply(&time, false.into()), 0.0.into()); + assert_eq!(modifier.apply(&time, true.into()), 0.1.into()); } #[test] - fn linear_axis3d() { + fn snapping() { let mut modifier = SmoothDelta::new(SmoothKind::Linear, 1.0); let mut time = Time::default(); time.advance_by(Duration::from_millis(100)); - assert_eq!( - modifier.apply(&time, Vec3::splat(0.5).into()), - Vec3::splat(0.057735026).into() - ); - assert_eq!( - modifier.apply(&time, Vec3::ONE.into()), - Vec3::splat(0.10969655).into() - ); - } - - #[test] - fn ease_function_axis3d() { - let mut modifier = SmoothDelta::new(EaseFunction::QuadraticIn, 1.0); - let mut time = Time::default(); - time.advance_by(Duration::from_millis(200)); + modifier.prev_value = Vec3::X * 0.99; + assert_eq!(modifier.apply(&time, 1.0.into()), 1.0.into()); - assert_eq!( - modifier.apply(&time, Vec3::splat(0.5).into()), - Vec3::splat(0.023094011).into() - ); - assert_eq!( - modifier.apply(&time, Vec3::ONE.into()), - Vec3::splat(0.045264263).into() - ); + modifier.prev_value = Vec3::X * 0.98; + assert_ne!(modifier.apply(&time, 1.0.into()), 1.0.into()); } }