diff --git a/crates/bevy_math/src/curve/easing.rs b/crates/bevy_math/src/curve/easing.rs index 981337e2ccec27..1334a6afa76dba 100644 --- a/crates/bevy_math/src/curve/easing.rs +++ b/crates/bevy_math/src/curve/easing.rs @@ -50,6 +50,8 @@ where #[inline] fn sample_unchecked(&self, t: f32) -> T { + let domain = self.easing.domain(); + let t = domain.start().lerp(domain.end(), t); self.start.lerp(self.end, self.easing.sample_unchecked(t)) } } @@ -62,8 +64,13 @@ where /// Create a new [`EasingCurve`] over the [unit interval] which transitions between a `start` /// and an `end` value based on the provided [`Easing`] curve. /// + /// If the input curve's domain is not the unit interval, then the [`EasingCurve`] will ensure + /// that this invariant is guaranteed by internally [reparametrizing] the curve to the unit + /// interval. + /// /// [unit interval]: `Interval::UNIT` - pub fn new(start: T, end: T, easing: E) -> EasingCurve { + /// [reparametrizing]: `Curve::reparametrize` + pub fn new(start: T, end: T, easing: E) -> Self { Self { start, end, easing } } } diff --git a/crates/bevy_math/src/curve/mod.rs b/crates/bevy_math/src/curve/mod.rs index 2836d22928854a..bd243151e3434e 100644 --- a/crates/bevy_math/src/curve/mod.rs +++ b/crates/bevy_math/src/curve/mod.rs @@ -1113,6 +1113,38 @@ mod tests { }); } + #[test] + fn easing_curve_non_unit_domain() { + let start = Vec2::ZERO; + let end = Vec2::new(1.0, 2.0); + + // even though the quadratic_ease_in input curve has the domain [0.0, 2.0], the easing + // curve correctly behaves as if its domain were [0.0, 1.0] + let curve = EasingCurve::new( + start, + end, + quadratic_ease_in().reparametrize(Interval::new(0.0, 2.0).unwrap(), |t| t / 2.0), + ); + + [ + (-0.1, None), + (0.0, Some(start)), + (0.25, Some(Vec2::new(0.0625, 0.125))), + (0.5, Some(Vec2::new(0.25, 0.5))), + (1.0, Some(end)), + (1.1, None), + ] + .into_iter() + .for_each(|(t, x)| { + let sample = curve.sample(t); + match (sample, x) { + (None, None) => assert_eq!(sample, x), + (Some(s), Some(x)) => assert!(s.abs_diff_eq(x, f32::EPSILON)), + _ => unreachable!(), + }; + }); + } + #[test] fn mapping() { let curve = function_curve(Interval::EVERYWHERE, |t| t * 3.0 + 1.0);