Skip to content

Commit e563f86

Browse files
authored
Simplified easing curves (#15711)
# Objective Simplify the API surrounding easing curves. Broaden the base of types that support easing. ## Solution There is now a single library function, `easing_curve`, which constructs a unit-parametrized easing curve between two values based on an `EaseFunction`: ```rust /// Given a `start` and `end` value, create a curve parametrized over [the unit interval] /// that connects them, using the given [ease function] to determine the form of the /// curve in between. /// /// [the unit interval]: Interval::UNIT /// [ease function]: EaseFunction pub fn easing_curve<T: Ease>(start: T, end: T, ease_fn: EaseFunction) -> EasingCurve<T> { //... } ``` As this shows, the type of the output curve is generic only in `T`. In particular, as long as `T` is `Reflect` (and `FromReflect` etc. — i.e., a standard "well-behaved" reflectable type), `EasingCurve<T>` is also `Reflect`, and there is no special field handling nonsense. Therefore, `EasingCurve` is the kind of thing that would be able to be easily changed in an editor. This is made possible by storing the actual `EaseFunction` on `EasingCurve<T>` instead of indirecting through some kind of function type (which generally leads to issues with reflection). The types that can be eased are those that implement a trait `Ease`: ```rust /// A type whose values can be eased between. /// /// This requires the construction of an interpolation curve that actually extends /// beyond the curve segment that connects two values, because an easing curve may /// extrapolate before the starting value and after the ending value. This is /// especially common in easing functions that mimic elastic or springlike behavior. pub trait Ease: Sized { /// Given `start` and `end` values, produce a curve with [unlimited domain] /// that: /// - takes a value equivalent to `start` at `t = 0` /// - takes a value equivalent to `end` at `t = 1` /// - has constant speed everywhere, including outside of `[0, 1]` /// /// [unlimited domain]: Interval::EVERYWHERE fn interpolating_curve_unbounded(start: &Self, end: &Self) -> impl Curve<Self>; } ``` (I know, I know, yet *another* interpolation trait. See 'Future direction'.) The other existing easing functions from the previous version of this module have also become new members of `EaseFunction`: `Linear`, `Steps`, and `Elastic` (which maybe needs a different name). The latter two are parametrized. ## Testing Tested using the `easing_functions` example. I also axed the `cubic_curve` example which was of questionable value and replaced it with `eased_motion`, which uses this API in the context of animation: https://github.com/user-attachments/assets/3c802992-6b9b-4b56-aeb1-a47501c29ce2 --- ## Future direction Morally speaking, `Ease` is incredibly similar to `StableInterpolate`. Probably, we should just merge `StableInterpolate` into `Ease`, and then make `SmoothNudge` an automatic extension trait of `Ease`. The reason I didn't do that is that `StableInterpolate` is not implemented for `VectorSpace` because of concerns about the `Color` types, and I wanted to avoid controversy. I think that may be a good idea though. As Alice mentioned before, we should also probably get rid of the `interpolation` dependency. The parametrized `Elastic` variant probably also needs some additional work (e.g. renaming, in/out/in-out variants, etc.) if we want to keep it.
1 parent 9aef71b commit e563f86

File tree

8 files changed

+408
-531
lines changed

8 files changed

+408
-531
lines changed

Cargo.toml

+5-5
Original file line numberDiff line numberDiff line change
@@ -1300,13 +1300,13 @@ category = "Animation"
13001300
wasm = true
13011301

13021302
[[example]]
1303-
name = "cubic_curve"
1304-
path = "examples/animation/cubic_curve.rs"
1303+
name = "eased_motion"
1304+
path = "examples/animation/eased_motion.rs"
13051305
doc-scrape-examples = true
13061306

1307-
[package.metadata.example.cubic_curve]
1308-
name = "Cubic Curve"
1309-
description = "Bezier curve example showing a cube following a cubic curve"
1307+
[package.metadata.example.eased_motion]
1308+
name = "Eased Motion"
1309+
description = "Demonstrates the application of easing curves to animate an object"
13101310
category = "Animation"
13111311
wasm = true
13121312

crates/bevy_math/src/common_traits.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,11 @@ pub trait VectorSpace:
4343
/// on the parameter `t`. When `t` is `0`, `self` is recovered. When `t` is `1`, `rhs`
4444
/// is recovered.
4545
///
46-
/// Note that the value of `t` is not clamped by this function, so interpolating outside
46+
/// Note that the value of `t` is not clamped by this function, so extrapolating outside
4747
/// of the interval `[0,1]` is allowed.
4848
#[inline]
49-
fn lerp(&self, rhs: Self, t: f32) -> Self {
50-
*self * (1. - t) + rhs * t
49+
fn lerp(self, rhs: Self, t: f32) -> Self {
50+
self * (1. - t) + rhs * t
5151
}
5252
}
5353

0 commit comments

Comments
 (0)