-
-
Notifications
You must be signed in to change notification settings - Fork 3.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
AnimatedProperty and AnimatedPropertyOptional #16484
base: main
Are you sure you want to change the base?
Conversation
I'd like to land this in 0.15 as it:
|
@@ -205,8 +274,7 @@ where | |||
P: AnimatableProperty, | |||
{ | |||
evaluator: BasicAnimationCurveEvaluator<P::Property>, | |||
#[reflect(ignore)] | |||
phantom: PhantomData<P>, | |||
property: P, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is basically my only concern with this PR.
Since evaluators are cached and dispatched based on type IDs, the previous setup with marker structs guaranteed that all AnimatableCurve
s accessing the same property would map to evaluators with the same type, since they used the same marker type as input.
Now, since AnimatedProperty
has a function-type generic F: Fn(&mut C) -> &mut P
, I think there is a subtle footgun involving the instantiation of evaluators: for example, if you create two AnimatableCurve
s using AnimatableProperty
s that are the same, but use closures to specify the property accessor, the two will map to distinct evaluator types, since the types (P
here) will actually be distinct. As a result, the outputs of those curves will not blend correctly (one will just overwrite the other, I think).
In other words, the previous implementation effectively guaranteed that the property accessors would be type-identical, and that is no longer the case now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(It might be enough to just warn about this and recommend defining the property in a large lexical scope and then reusing it in calls to AnimatableCurve::new
; if anything, I'm mostly pointing out that the pattern described in the 'Solution' section of the PR description is subtly an anti-pattern.)
There are a few things that I would do differently here. First, I would define a getter and setter rather than returning a mutable field. This would allow the property being animated to be a simplified abstraction of the underlying property. So for example, I could animate rotation_x as an angle instead of having to deal with a quat - the conversion from angle to quat could be done in the AnimatableProperty impl. Similarly, I could animate scale as a scalar affecting all dimensions instead of separate scale_x, scale_y, scale_z. See also the discussion in #15725 - there's a difference between "keyframe" curves and "transition" curves (my terms, perhaps there's a better way of describing this), in that the animation target can change in mid-animation (like a button which inflates when hovered, but the mouse quickly enters and leaves, giving no time for the animation to complete). In thee cases, you want to avoid an ugly jump from resetting the animation back to start, and instead start the animation from whatever the current state is. |
Objective
Animating component properties requires too much boilerplate at the moment:
Solution
This adds
AnimatedProperty
andAnimatedPropertyOptional
, enabling the following:This required reworking the internals a bit, namely stripping out a lot of the
Reflect
usage, as that implementation was fundamentally incompatible with theAnimatedProperty
pattern.Reflect
was being used in this context just to downcast traits. But we can get downcasting behavior without theReflect
requirement by implementingDowncast
forAnimationCurveEvaluator
.