Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_animation/src/animation_curves.rs
9441 views
1
//! The [`AnimationCurve`] trait and adaptors that allow curves to implement it.
2
//!
3
//! # Overview
4
//!
5
//! The flow of curves into the animation system generally begins with something that
6
//! implements the [`Curve`] trait. Let's imagine, for example, that we have some
7
//! `Curve<Vec3>` that we want to use to animate something. That could be defined in
8
//! a number of different ways, but let's imagine that we've defined it [using a function]:
9
//!
10
//! # use bevy_math::curve::{Curve, Interval, FunctionCurve};
11
//! # use bevy_math::vec3;
12
//! let wobble_curve = FunctionCurve::new(
13
//! Interval::UNIT,
14
//! |t| { vec3(t.cos(), 0.0, 0.0) },
15
//! );
16
//!
17
//! Okay, so we have a curve, but the animation system also needs to know, in some way,
18
//! how the values from this curve should actually be used. That is, it needs to know what
19
//! to animate! That's what [`AnimationCurve`] is for. In particular, what we need to do
20
//! is take our curve and turn it into an `AnimationCurve` which will be usable by the
21
//! animation system.
22
//!
23
//! For instance, let's imagine that we want to use the `Vec3` output
24
//! from our curve to animate the [translation component of a `Transform`]. For this, there is
25
//! the adaptor [`AnimatableCurve`], which wraps any [`Curve`] and [`AnimatableProperty`] and turns it into an
26
//! [`AnimationCurve`] that will use the given curve to animate the entity's property:
27
//!
28
//! # use bevy_math::curve::{Curve, Interval, FunctionCurve};
29
//! # use bevy_math::vec3;
30
//! # use bevy_transform::components::Transform;
31
//! # use bevy_animation::{animated_field, animation_curves::*};
32
//! # let wobble_curve = FunctionCurve::new(
33
//! # Interval::UNIT,
34
//! # |t| vec3(t.cos(), 0.0, 0.0)
35
//! # );
36
//! let wobble_animation = AnimatableCurve::new(animated_field!(Transform::translation), wobble_curve);
37
//!
38
//! And finally, this [`AnimationCurve`] needs to be added to an [`AnimationClip`] in order to
39
//! actually animate something. This is what that looks like:
40
//!
41
//! # use bevy_math::curve::{Curve, Interval, FunctionCurve};
42
//! # use bevy_animation::{AnimationClip, AnimationTargetId, animated_field, animation_curves::*};
43
//! # use bevy_transform::components::Transform;
44
//! # use bevy_ecs::name::Name;
45
//! # use bevy_math::vec3;
46
//! # let wobble_curve = FunctionCurve::new(
47
//! # Interval::UNIT,
48
//! # |t| { vec3(t.cos(), 0.0, 0.0) },
49
//! # );
50
//! # let wobble_animation = AnimatableCurve::new(animated_field!(Transform::translation), wobble_curve);
51
//! # let animation_target_id = AnimationTargetId::from(&Name::new("Test"));
52
//! let mut animation_clip = AnimationClip::default();
53
//! animation_clip.add_curve_to_target(
54
//! animation_target_id,
55
//! wobble_animation,
56
//! );
57
//!
58
//! # Making animation curves
59
//!
60
//! The overview showed one example, but in general there are a few different ways of going from
61
//! a [`Curve`], which produces time-related data of some kind, to an [`AnimationCurve`], which
62
//! knows how to apply that data to an entity.
63
//!
64
//! ## Animated Fields
65
//!
66
//! The [`animated_field`] macro (which returns an [`AnimatedField`]), in combination with [`AnimatableCurve`]
67
//! is the easiest way to make an animation curve (see the example above).
68
//!
69
//! This will select a field on a component and pass it to a [`Curve`] with a type that matches the field.
70
//!
71
//! ## Animatable Properties
72
//!
73
//! Animation of arbitrary aspects of entities can be accomplished using [`AnimatableProperty`] in
74
//! conjunction with [`AnimatableCurve`]. See the documentation [there] for details.
75
//!
76
//! ## Custom [`AnimationCurve`] and [`AnimationCurveEvaluator`]
77
//!
78
//! This is the lowest-level option with the most control, but it is also the most complicated.
79
//!
80
//! [using a function]: bevy_math::curve::FunctionCurve
81
//! [translation component of a `Transform`]: bevy_transform::prelude::Transform::translation
82
//! [`AnimationClip`]: crate::AnimationClip
83
//! [there]: AnimatableProperty
84
//! [`animated_field`]: crate::animated_field
85
86
use core::{
87
any::TypeId,
88
fmt::{self, Debug, Formatter},
89
marker::PhantomData,
90
};
91
92
#[cfg(feature = "bevy_mesh")]
93
pub use crate::morph::*;
94
use crate::{
95
graph::AnimationNodeIndex,
96
prelude::{Animatable, BlendInput},
97
AnimationEntityMut, AnimationEvaluationError,
98
};
99
use bevy_ecs::component::{Component, Mutable};
100
use bevy_math::curve::{
101
cores::{UnevenCore, UnevenCoreError},
102
Curve, Interval,
103
};
104
use bevy_platform::hash::Hashed;
105
use bevy_reflect::{FromReflect, Reflect, Reflectable, TypeInfo, Typed};
106
use downcast_rs::{impl_downcast, Downcast};
107
108
/// A trait for exposing a value in an entity so that it can be animated.
109
///
110
/// `AnimatableProperty` allows any value contained in an entity to be animated
111
/// as long as it can be obtained by mutable reference. This makes it more
112
/// flexible than [`animated_field`].
113
///
114
/// [`animated_field`]: crate::animated_field
115
///
116
/// Here, `AnimatableProperty` is used to animate a value inside an `Option`,
117
/// returning an error if the option is `None`.
118
///
119
/// # use bevy_animation::{prelude::AnimatableProperty, AnimationEntityMut, AnimationEvaluationError, animation_curves::EvaluatorId};
120
/// # use bevy_ecs::component::Component;
121
/// # use std::any::TypeId;
122
/// #[derive(Component)]
123
/// struct ExampleComponent {
124
/// power_level: Option<f32>
125
/// }
126
///
127
/// #[derive(Clone)]
128
/// struct PowerLevelProperty;
129
///
130
/// impl AnimatableProperty for PowerLevelProperty {
131
/// type Property = f32;
132
/// fn get_mut<'a>(
133
/// &self,
134
/// entity: &'a mut AnimationEntityMut
135
/// ) -> Result<&'a mut Self::Property, AnimationEvaluationError> {
136
/// let component = entity
137
/// .get_mut::<ExampleComponent>()
138
/// .ok_or(AnimationEvaluationError::ComponentNotPresent(
139
/// TypeId::of::<ExampleComponent>()
140
/// ))?
141
/// .into_inner();
142
/// component.power_level.as_mut().ok_or(AnimationEvaluationError::PropertyNotPresent(
143
/// TypeId::of::<Option<f32>>()
144
/// ))
145
/// }
146
///
147
/// fn evaluator_id(&self) -> EvaluatorId {
148
/// EvaluatorId::Type(TypeId::of::<Self>())
149
/// }
150
/// }
151
///
152
///
153
/// You can then create an [`AnimatableCurve`] to animate this property like so:
154
///
155
/// # use bevy_animation::{VariableCurve, AnimationEntityMut, AnimationEvaluationError, animation_curves::EvaluatorId};
156
/// # use bevy_animation::prelude::{AnimatableProperty, AnimatableKeyframeCurve, AnimatableCurve};
157
/// # use bevy_ecs::{name::Name, component::Component};
158
/// # use std::any::TypeId;
159
/// # #[derive(Component)]
160
/// # struct ExampleComponent { power_level: Option<f32> }
161
/// # #[derive(Clone)]
162
/// # struct PowerLevelProperty;
163
/// # impl AnimatableProperty for PowerLevelProperty {
164
/// # type Property = f32;
165
/// # fn get_mut<'a>(
166
/// # &self,
167
/// # entity: &'a mut AnimationEntityMut
168
/// # ) -> Result<&'a mut Self::Property, AnimationEvaluationError> {
169
/// # let component = entity
170
/// # .get_mut::<ExampleComponent>()
171
/// # .ok_or(AnimationEvaluationError::ComponentNotPresent(
172
/// # TypeId::of::<ExampleComponent>()
173
/// # ))?
174
/// # .into_inner();
175
/// # component.power_level.as_mut().ok_or(AnimationEvaluationError::PropertyNotPresent(
176
/// # TypeId::of::<Option<f32>>()
177
/// # ))
178
/// # }
179
/// # fn evaluator_id(&self) -> EvaluatorId {
180
/// # EvaluatorId::Type(TypeId::of::<Self>())
181
/// # }
182
/// # }
183
/// AnimatableCurve::new(
184
/// PowerLevelProperty,
185
/// AnimatableKeyframeCurve::new([
186
/// (0.0, 0.0),
187
/// (1.0, 9001.0),
188
/// ]).expect("Failed to create power level curve")
189
/// );
190
pub trait AnimatableProperty: Send + Sync + 'static {
191
/// The animated property type.
192
type Property: Animatable;
193
194
/// Retrieves the property from the given `entity`.
195
fn get_mut<'a>(
196
&self,
197
entity: &'a mut AnimationEntityMut,
198
) -> Result<&'a mut Self::Property, AnimationEvaluationError>;
199
200
/// The [`EvaluatorId`] used to look up the [`AnimationCurveEvaluator`] for this [`AnimatableProperty`].
201
/// For a given animated property, this ID should always be the same to allow things like animation blending to occur.
202
fn evaluator_id(&self) -> EvaluatorId<'_>;
203
}
204
205
/// A [`Component`] field that can be animated, defined by a function that reads the component and returns
206
/// the accessed field / property.
207
///
208
/// The best way to create an instance of this type is via the [`animated_field`] macro.
209
///
210
/// `C` is the component being animated, `A` is the type of the [`Animatable`] field on the component, and `F` is an accessor
211
/// function that accepts a reference to `C` and retrieves the field `A`.
212
///
213
/// [`animated_field`]: crate::animated_field
214
#[derive(Clone)]
215
pub struct AnimatedField<C, A, F: Fn(&mut C) -> &mut A> {
216
func: F,
217
/// A pre-hashed (component-type-id, reflected-field-index) pair, uniquely identifying a component field
218
evaluator_id: Hashed<(TypeId, usize)>,
219
marker: PhantomData<(C, A)>,
220
}
221
222
impl<C, A, F> AnimatableProperty for AnimatedField<C, A, F>
223
where
224
C: Component<Mutability = Mutable>,
225
A: Animatable + Clone + Sync + Debug,
226
F: Fn(&mut C) -> &mut A + Send + Sync + 'static,
227
{
228
type Property = A;
229
fn get_mut<'a>(
230
&self,
231
entity: &'a mut AnimationEntityMut,
232
) -> Result<&'a mut A, AnimationEvaluationError> {
233
let c = entity
234
.get_mut::<C>()
235
.ok_or_else(|| AnimationEvaluationError::ComponentNotPresent(TypeId::of::<C>()))?;
236
Ok((self.func)(c.into_inner()))
237
}
238
239
fn evaluator_id(&self) -> EvaluatorId<'_> {
240
EvaluatorId::ComponentField(&self.evaluator_id)
241
}
242
}
243
244
impl<C: Typed, P, F: Fn(&mut C) -> &mut P + 'static> AnimatedField<C, P, F> {
245
/// Creates a new instance of [`AnimatedField`]. This operates under the assumption that
246
/// `C` is a reflect-able struct, and that `field_name` is a valid field on that struct.
247
///
248
/// # Panics
249
/// If the type of `C` is not a struct or if the `field_name` does not exist.
250
pub fn new_unchecked(field_name: &str, func: F) -> Self {
251
let field_index;
252
if let TypeInfo::Struct(struct_info) = C::type_info() {
253
field_index = struct_info
254
.index_of(field_name)
255
.expect("Field name should exist");
256
} else if let TypeInfo::TupleStruct(struct_info) = C::type_info() {
257
field_index = field_name
258
.parse()
259
.expect("Field name should be a valid tuple index");
260
if field_index >= struct_info.field_len() {
261
panic!("Field name should be a valid tuple index");
262
}
263
} else {
264
panic!("Only structs are supported in `AnimatedField::new_unchecked`")
265
}
266
267
Self {
268
func,
269
evaluator_id: Hashed::new((TypeId::of::<C>(), field_index)),
270
marker: PhantomData,
271
}
272
}
273
}
274
275
/// This trait collects the additional requirements on top of [`Curve<T>`] needed for a
276
/// curve to be used as an [`AnimationCurve`].
277
pub trait AnimationCompatibleCurve<T>: Curve<T> + Debug + Clone + Reflectable {}
278
279
impl<T, C> AnimationCompatibleCurve<T> for C where C: Curve<T> + Debug + Clone + Reflectable {}
280
281
/// This type allows the conversion of a [curve] valued in the [property type] of an
282
/// [`AnimatableProperty`] into an [`AnimationCurve`] which animates that property.
283
///
284
/// [curve]: Curve
285
/// [property type]: AnimatableProperty::Property
286
#[derive(Reflect, FromReflect)]
287
#[reflect(from_reflect = false)]
288
pub struct AnimatableCurve<P, C> {
289
/// The property selector, which defines what component to access and how to access
290
/// a property on that component.
291
pub property: P,
292
293
/// The inner [curve] whose values are used to animate the property.
294
///
295
/// [curve]: Curve
296
pub curve: C,
297
}
298
299
/// An [`AnimatableCurveEvaluator`] for [`AnimatableProperty`] instances.
300
///
301
/// You shouldn't ordinarily need to instantiate one of these manually. Bevy
302
/// will automatically do so when you use an [`AnimatableCurve`] instance.
303
#[derive(Reflect)]
304
pub struct AnimatableCurveEvaluator<A: Animatable> {
305
evaluator: BasicAnimationCurveEvaluator<A>,
306
property: Box<dyn AnimatableProperty<Property = A>>,
307
}
308
309
impl<P, C> AnimatableCurve<P, C>
310
where
311
P: AnimatableProperty,
312
C: AnimationCompatibleCurve<P::Property>,
313
{
314
/// Create an [`AnimatableCurve`] (and thus an [`AnimationCurve`]) from a curve
315
/// valued in an [animatable property].
316
///
317
/// [animatable property]: AnimatableProperty::Property
318
pub fn new(property: P, curve: C) -> Self {
319
Self { property, curve }
320
}
321
}
322
323
impl<P, C> Clone for AnimatableCurve<P, C>
324
where
325
C: Clone,
326
P: Clone,
327
{
328
fn clone(&self) -> Self {
329
Self {
330
curve: self.curve.clone(),
331
property: self.property.clone(),
332
}
333
}
334
}
335
336
impl<P, C> Debug for AnimatableCurve<P, C>
337
where
338
C: Debug,
339
{
340
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
341
f.debug_struct("AnimatableCurve")
342
.field("curve", &self.curve)
343
.finish()
344
}
345
}
346
347
impl<P: Send + Sync + 'static, C> AnimationCurve for AnimatableCurve<P, C>
348
where
349
P: AnimatableProperty + Clone,
350
C: AnimationCompatibleCurve<P::Property> + Clone,
351
{
352
fn clone_value(&self) -> Box<dyn AnimationCurve> {
353
Box::new(self.clone())
354
}
355
356
fn domain(&self) -> Interval {
357
self.curve.domain()
358
}
359
360
fn evaluator_id(&self) -> EvaluatorId<'_> {
361
self.property.evaluator_id()
362
}
363
364
fn create_evaluator(&self) -> Box<dyn AnimationCurveEvaluator> {
365
Box::new(AnimatableCurveEvaluator::<P::Property> {
366
evaluator: BasicAnimationCurveEvaluator::default(),
367
property: Box::new(self.property.clone()),
368
})
369
}
370
371
fn apply(
372
&self,
373
curve_evaluator: &mut dyn AnimationCurveEvaluator,
374
t: f32,
375
weight: f32,
376
graph_node: AnimationNodeIndex,
377
) -> Result<(), AnimationEvaluationError> {
378
let curve_evaluator = curve_evaluator
379
.downcast_mut::<AnimatableCurveEvaluator<P::Property>>()
380
.unwrap();
381
let value = self.curve.sample_clamped(t);
382
curve_evaluator
383
.evaluator
384
.stack
385
.push(BasicAnimationCurveEvaluatorStackElement {
386
value,
387
weight,
388
graph_node,
389
});
390
Ok(())
391
}
392
}
393
394
impl<A: Animatable> AnimationCurveEvaluator for AnimatableCurveEvaluator<A> {
395
fn blend(&mut self, graph_node: AnimationNodeIndex) -> Result<(), AnimationEvaluationError> {
396
self.evaluator.combine(graph_node, /*additive=*/ false)
397
}
398
399
fn add(&mut self, graph_node: AnimationNodeIndex) -> Result<(), AnimationEvaluationError> {
400
self.evaluator.combine(graph_node, /*additive=*/ true)
401
}
402
403
fn push_blend_register(
404
&mut self,
405
weight: f32,
406
graph_node: AnimationNodeIndex,
407
) -> Result<(), AnimationEvaluationError> {
408
self.evaluator.push_blend_register(weight, graph_node)
409
}
410
411
fn commit(&mut self, mut entity: AnimationEntityMut) -> Result<(), AnimationEvaluationError> {
412
let property = self.property.get_mut(&mut entity)?;
413
*property = self
414
.evaluator
415
.stack
416
.pop()
417
.ok_or_else(inconsistent::<AnimatableCurveEvaluator<A>>)?
418
.value;
419
self.evaluator.stack.clear();
420
Ok(())
421
}
422
}
423
424
#[derive(Reflect)]
425
struct BasicAnimationCurveEvaluator<A>
426
where
427
A: Animatable,
428
{
429
stack: Vec<BasicAnimationCurveEvaluatorStackElement<A>>,
430
blend_register: Option<(A, f32)>,
431
}
432
433
#[derive(Reflect)]
434
struct BasicAnimationCurveEvaluatorStackElement<A>
435
where
436
A: Animatable,
437
{
438
value: A,
439
weight: f32,
440
graph_node: AnimationNodeIndex,
441
}
442
443
impl<A> Default for BasicAnimationCurveEvaluator<A>
444
where
445
A: Animatable,
446
{
447
fn default() -> Self {
448
BasicAnimationCurveEvaluator {
449
stack: vec![],
450
blend_register: None,
451
}
452
}
453
}
454
455
impl<A> BasicAnimationCurveEvaluator<A>
456
where
457
A: Animatable,
458
{
459
fn combine(
460
&mut self,
461
graph_node: AnimationNodeIndex,
462
additive: bool,
463
) -> Result<(), AnimationEvaluationError> {
464
let Some(top) = self.stack.last() else {
465
return Ok(());
466
};
467
if top.graph_node != graph_node {
468
return Ok(());
469
}
470
471
let BasicAnimationCurveEvaluatorStackElement {
472
value: value_to_blend,
473
weight: weight_to_blend,
474
graph_node: _,
475
} = self.stack.pop().unwrap();
476
477
match self.blend_register.take() {
478
None => {
479
self.initialize_blend_register(value_to_blend, weight_to_blend, additive);
480
}
481
Some((mut current_value, mut current_weight)) => {
482
current_weight += weight_to_blend;
483
484
if additive {
485
current_value = A::blend(
486
[
487
BlendInput {
488
weight: 1.0,
489
value: current_value,
490
additive: true,
491
},
492
BlendInput {
493
weight: weight_to_blend,
494
value: value_to_blend,
495
additive: true,
496
},
497
]
498
.into_iter(),
499
);
500
} else {
501
current_value = A::interpolate(
502
&current_value,
503
&value_to_blend,
504
weight_to_blend / current_weight,
505
);
506
}
507
508
self.blend_register = Some((current_value, current_weight));
509
}
510
}
511
512
Ok(())
513
}
514
515
fn initialize_blend_register(&mut self, value: A, weight: f32, additive: bool) {
516
if additive {
517
let scaled_value = A::blend(
518
[BlendInput {
519
weight,
520
value,
521
additive: true,
522
}]
523
.into_iter(),
524
);
525
self.blend_register = Some((scaled_value, weight));
526
} else {
527
self.blend_register = Some((value, weight));
528
}
529
}
530
531
fn push_blend_register(
532
&mut self,
533
weight: f32,
534
graph_node: AnimationNodeIndex,
535
) -> Result<(), AnimationEvaluationError> {
536
if let Some((value, _)) = self.blend_register.take() {
537
self.stack.push(BasicAnimationCurveEvaluatorStackElement {
538
value,
539
weight,
540
graph_node,
541
});
542
}
543
Ok(())
544
}
545
}
546
547
/// A low-level trait that provides control over how curves are actually applied
548
/// to entities by the animation system.
549
///
550
/// Typically, this will not need to be implemented manually, since it is
551
/// automatically implemented by [`AnimatableCurve`] and other curves used by
552
/// the animation system (e.g. those that animate parts of transforms or morph
553
/// weights). However, this can be implemented manually when `AnimatableCurve`
554
/// is not sufficiently expressive.
555
///
556
/// In many respects, this behaves like a type-erased form of [`Curve`], where
557
/// the output type of the curve is remembered only in the components that are
558
/// mutated in the implementation of [`apply`].
559
///
560
/// [`apply`]: AnimationCurve::apply
561
pub trait AnimationCurve: Debug + Send + Sync + 'static {
562
/// Returns a boxed clone of this value.
563
fn clone_value(&self) -> Box<dyn AnimationCurve>;
564
565
/// The range of times for which this animation is defined.
566
fn domain(&self) -> Interval;
567
568
/// Returns the type ID of the [`AnimationCurveEvaluator`].
569
///
570
/// This must match the type returned by [`Self::create_evaluator`]. It must
571
/// be a single type that doesn't depend on the type of the curve.
572
fn evaluator_id(&self) -> EvaluatorId<'_>;
573
574
/// Returns a newly-instantiated [`AnimationCurveEvaluator`] for use with
575
/// this curve.
576
///
577
/// All curve types must return the same type of
578
/// [`AnimationCurveEvaluator`]. The returned value must match the type
579
/// returned by [`Self::evaluator_id`].
580
fn create_evaluator(&self) -> Box<dyn AnimationCurveEvaluator>;
581
582
/// Samples the curve at the given time `t`, and pushes the sampled value
583
/// onto the evaluation stack of the `curve_evaluator`.
584
///
585
/// The `curve_evaluator` parameter points to the value returned by
586
/// [`Self::create_evaluator`], upcast to an `&mut dyn
587
/// AnimationCurveEvaluator`. Typically, implementations of [`Self::apply`]
588
/// will want to downcast the `curve_evaluator` parameter to the concrete
589
/// type [`Self::evaluator_id`] in order to push values of the appropriate
590
/// type onto its evaluation stack.
591
///
592
/// Be sure not to confuse the `t` and `weight` values. The former
593
/// determines the position at which the *curve* is sampled, while `weight`
594
/// ultimately determines how much the *stack values* will be blended
595
/// together (see the definition of [`AnimationCurveEvaluator::blend`]).
596
fn apply(
597
&self,
598
curve_evaluator: &mut dyn AnimationCurveEvaluator,
599
t: f32,
600
weight: f32,
601
graph_node: AnimationNodeIndex,
602
) -> Result<(), AnimationEvaluationError>;
603
}
604
605
/// The [`EvaluatorId`] is used to look up the [`AnimationCurveEvaluator`] for an [`AnimatableProperty`].
606
/// For a given animated property, this ID should always be the same to allow things like animation blending to occur.
607
#[derive(Clone)]
608
pub enum EvaluatorId<'a> {
609
/// Corresponds to a specific field on a specific component type.
610
/// The `TypeId` should correspond to the component type, and the `usize`
611
/// should correspond to the Reflect-ed field index of the field.
612
//
613
// IMPLEMENTATION NOTE: The Hashed<(TypeId, usize) is intentionally cheap to clone, as it will be cloned per frame by the evaluator
614
// Switching the field index `usize` for something like a field name `String` would probably be too expensive to justify
615
ComponentField(&'a Hashed<(TypeId, usize)>),
616
/// Corresponds to a custom property of a given type. This should be the [`TypeId`]
617
/// of the custom [`AnimatableProperty`].
618
Type(TypeId),
619
}
620
621
/// A low-level trait for use in [`VariableCurve`](`crate::VariableCurve`) that provides fine
622
/// control over how animations are evaluated.
623
///
624
/// You can implement this trait when the generic [`AnimatableCurveEvaluator`]
625
/// isn't sufficiently-expressive for your needs. For example, `MorphWeights`
626
/// implements this trait instead of using [`AnimatableCurveEvaluator`] because
627
/// it needs to animate arbitrarily many weights at once, which can't be done
628
/// with [`Animatable`] as that works on fixed-size values only.
629
///
630
/// If you implement this trait, you should also implement [`AnimationCurve`] on
631
/// your curve type, as that trait allows creating instances of this one.
632
///
633
/// Implementations of [`AnimatableCurveEvaluator`] should maintain a *stack* of
634
/// (value, weight, node index) triples, as well as a *blend register*, which is
635
/// either a (value, weight) pair or empty. *Value* here refers to an instance
636
/// of the value being animated: for example, [`Vec3`] in the case of
637
/// translation keyframes. The stack stores intermediate values generated while
638
/// evaluating the [`AnimationGraph`](`crate::graph::AnimationGraph`), while the blend register
639
/// stores the result of a blend operation.
640
///
641
/// [`Vec3`]: bevy_math::Vec3
642
pub trait AnimationCurveEvaluator: Downcast + Send + Sync + 'static {
643
/// Blends the top element of the stack with the blend register.
644
///
645
/// The semantics of this method are as follows:
646
///
647
/// 1. Pop the top element of the stack. Call its value vₘ and its weight
648
/// wₘ. If the stack was empty, return success.
649
///
650
/// 2. If the blend register is empty, set the blend register value to vₘ
651
/// and the blend register weight to wₘ; then, return success.
652
///
653
/// 3. If the blend register is nonempty, call its current value vₙ and its
654
/// current weight wₙ. Then, set the value of the blend register to
655
/// `interpolate(vₙ, vₘ, wₘ / (wₘ + wₙ))`, and set the weight of the blend
656
/// register to wₘ + wₙ.
657
///
658
/// 4. Return success.
659
fn blend(&mut self, graph_node: AnimationNodeIndex) -> Result<(), AnimationEvaluationError>;
660
661
/// Additively blends the top element of the stack with the blend register.
662
///
663
/// The semantics of this method are as follows:
664
///
665
/// 1. Pop the top element of the stack. Call its value vₘ and its weight
666
/// wₘ. If the stack was empty, return success.
667
///
668
/// 2. If the blend register is empty, set the blend register value to vₘ
669
/// and the blend register weight to wₘ; then, return success.
670
///
671
/// 3. If the blend register is nonempty, call its current value vₙ.
672
/// Then, set the value of the blend register to vₙ + vₘwₘ.
673
///
674
/// 4. Return success.
675
fn add(&mut self, graph_node: AnimationNodeIndex) -> Result<(), AnimationEvaluationError>;
676
677
/// Pushes the current value of the blend register onto the stack.
678
///
679
/// If the blend register is empty, this method does nothing successfully.
680
/// Otherwise, this method pushes the current value of the blend register
681
/// onto the stack, alongside the weight and graph node supplied to this
682
/// function. The weight present in the blend register is discarded; only
683
/// the weight parameter to this function is pushed onto the stack. The
684
/// blend register is emptied after this process.
685
fn push_blend_register(
686
&mut self,
687
weight: f32,
688
graph_node: AnimationNodeIndex,
689
) -> Result<(), AnimationEvaluationError>;
690
691
/// Pops the top value off the stack and writes it into the appropriate
692
/// component.
693
///
694
/// If the stack is empty, this method does nothing successfully. Otherwise,
695
/// it pops the top value off the stack, fetches the associated component
696
/// from either the `transform` or `entity` values as appropriate, and
697
/// updates the appropriate property with the value popped from the stack.
698
/// The weight and node index associated with the popped stack element are
699
/// discarded. After doing this, the stack is emptied.
700
///
701
/// The property on the component must be overwritten with the value from
702
/// the stack, not blended with it.
703
fn commit(&mut self, entity: AnimationEntityMut) -> Result<(), AnimationEvaluationError>;
704
}
705
706
impl_downcast!(AnimationCurveEvaluator);
707
708
/// A [curve] defined by keyframes with values in an [animatable] type.
709
///
710
/// The keyframes are interpolated using the type's [`Animatable::interpolate`] implementation.
711
///
712
/// [curve]: Curve
713
/// [animatable]: Animatable
714
#[derive(Debug, Clone, Reflect)]
715
pub struct AnimatableKeyframeCurve<T> {
716
core: UnevenCore<T>,
717
}
718
719
impl<T> Curve<T> for AnimatableKeyframeCurve<T>
720
where
721
T: Animatable + Clone,
722
{
723
#[inline]
724
fn domain(&self) -> Interval {
725
self.core.domain()
726
}
727
728
#[inline]
729
fn sample_clamped(&self, t: f32) -> T {
730
// `UnevenCore::sample_with` is implicitly clamped.
731
self.core.sample_with(t, <T as Animatable>::interpolate)
732
}
733
734
#[inline]
735
fn sample_unchecked(&self, t: f32) -> T {
736
self.sample_clamped(t)
737
}
738
}
739
740
impl<T> AnimatableKeyframeCurve<T>
741
where
742
T: Animatable,
743
{
744
/// Create a new [`AnimatableKeyframeCurve`] from the given `keyframes`. The values of this
745
/// curve are interpolated from the keyframes using the output type's implementation of
746
/// [`Animatable::interpolate`].
747
///
748
/// There must be at least two samples in order for this method to succeed.
749
pub fn new(keyframes: impl IntoIterator<Item = (f32, T)>) -> Result<Self, UnevenCoreError> {
750
Ok(Self {
751
core: UnevenCore::new(keyframes)?,
752
})
753
}
754
}
755
756
fn inconsistent<P>() -> AnimationEvaluationError
757
where
758
P: 'static + ?Sized,
759
{
760
AnimationEvaluationError::InconsistentEvaluatorImplementation(TypeId::of::<P>())
761
}
762
763
/// Returns an [`AnimatedField`] with a given `$component` and `$field`.
764
///
765
/// This can be used in the following way:
766
///
767
/// ```
768
/// # use bevy_animation::{animation_curves::AnimatedField, animated_field};
769
/// # use bevy_color::Srgba;
770
/// # use bevy_ecs::component::Component;
771
/// # use bevy_math::Vec3;
772
/// # use bevy_reflect::Reflect;
773
/// #[derive(Component, Reflect)]
774
/// struct Transform {
775
/// translation: Vec3,
776
/// }
777
///
778
/// let field = animated_field!(Transform::translation);
779
///
780
/// #[derive(Component, Reflect)]
781
/// struct Color(Srgba);
782
///
783
/// let tuple_field = animated_field!(Color::0);
784
/// ```
785
#[macro_export]
786
macro_rules! animated_field {
787
($component:ident::$field:tt) => {
788
AnimatedField::new_unchecked(stringify!($field), |component: &mut $component| {
789
&mut component.$field
790
})
791
};
792
}
793
794
#[cfg(test)]
795
mod tests {
796
use super::*;
797
798
#[test]
799
fn test_animated_field_tuple_struct_simple_uses() {
800
#[derive(Clone, Debug, Component, Reflect)]
801
struct A(f32);
802
let _ = AnimatedField::new_unchecked("0", |a: &mut A| &mut a.0);
803
804
#[derive(Clone, Debug, Component, Reflect)]
805
struct B(f32, f64, f32);
806
let _ = AnimatedField::new_unchecked("0", |b: &mut B| &mut b.0);
807
let _ = AnimatedField::new_unchecked("1", |b: &mut B| &mut b.1);
808
let _ = AnimatedField::new_unchecked("2", |b: &mut B| &mut b.2);
809
}
810
}
811
812