bevy/crates/bevy_utils/src
Carter Anderson e4c8bb92db AnimatedField and Rework Evaluators (#16484)
# Objective

Animating component fields requires too much boilerplate at the moment:

```rust
#[derive(Reflect)]
struct FontSizeProperty;

impl AnimatableProperty for FontSizeProperty {
    type Component = TextFont;

    type Property = f32;

    fn get_mut(component: &mut Self::Component) -> Option<&mut Self::Property> {
        Some(&mut component.font_size)
    }
}

animation_clip.add_curve_to_target(
    animation_target_id,
    AnimatableKeyframeCurve::new(
        [0.0, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0]
            .into_iter()
            .zip([24.0, 80.0, 24.0, 80.0, 24.0, 80.0, 24.0]),
    )
    .map(AnimatableCurve::<FontSizeProperty, _>::from_curve)
    .expect("should be able to build translation curve because we pass in valid samples"),
);
```

## Solution

This adds `AnimatedField` and an `animated_field!` macro, enabling the
following:

```rust
animation_clip.add_curve_to_target(
    animation_target_id,
    AnimatableCurve::new(
        animated_field!(TextFont::font_size),
        AnimatableKeyframeCurve::new(
            [0.0, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0]
                .into_iter()
                .zip([24.0, 80.0, 24.0, 80.0, 24.0, 80.0, 24.0]),
        )
        .expect(
            "should be able to build translation curve because we pass in valid samples",
        ),
    ),
);
```

This required reworking the internals a bit, namely stripping out a lot
of the `Reflect` usage, as that implementation was fundamentally
incompatible with the `AnimatedField` pattern. `Reflect` was being used
in this context just to downcast traits. But we can get downcasting
behavior without the `Reflect` requirement by implementing `Downcast`
for `AnimationCurveEvaluator`.

This also reworks "evaluator identity" to support either a (Component /
Field) pair, or a TypeId. This allows properties to reuse evaluators,
even if they have different accessor methods. The "contract" here is
that for a given (Component / Field) pair, the accessor will return the
same value. Fields are identified by their Reflect-ed field index. The
(TypeId, usize) is prehashed and cached to optimize for lookup speed.

This removes the built-in hard-coded TranslationCurve / RotationCurve /
ScaleCurve in favor of AnimatableField.

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2024-11-28 00:23:01 +01:00
..
default.rs Simpler lint fixes: makes ci lints work but disables a lint for now (#15376) 2024-09-24 11:42:59 +00:00
futures.rs Allow bevy_utils in no_std Contexts (#15279) 2024-09-18 16:00:03 +00:00
lib.rs AnimatedField and Rework Evaluators (#16484) 2024-11-28 00:23:01 +01:00
object_safe.rs Add mappings to EntityMapper (#13727) 2024-06-08 12:52:23 +00:00
once.rs Add core and alloc over std Lints (#15281) 2024-09-27 00:59:59 +00:00
parallel_queue.rs Allow bevy_utils in no_std Contexts (#15279) 2024-09-18 16:00:03 +00:00
synccell.rs Allow bevy_utils in no_std Contexts (#15279) 2024-09-18 16:00:03 +00:00
syncunsafecell.rs
time.rs Minor fixes for bevy_utils in no_std (#15463) 2024-10-04 19:25:49 +00:00