Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_animation/src/lib.rs
9353 views
1
#![cfg_attr(docsrs, feature(doc_cfg))]
2
#![warn(unsafe_code)]
3
#![doc(
4
html_logo_url = "https://bevy.org/assets/icon.png",
5
html_favicon_url = "https://bevy.org/assets/icon.png"
6
)]
7
8
//! Animation for the game engine Bevy
9
10
extern crate alloc;
11
12
pub mod animatable;
13
pub mod animation_curves;
14
pub mod gltf_curves;
15
pub mod graph;
16
#[cfg(feature = "bevy_mesh")]
17
mod morph;
18
pub mod transition;
19
20
mod animation_event;
21
mod util;
22
23
pub use animation_event::*;
24
25
use core::{
26
any::TypeId,
27
cell::RefCell,
28
fmt::Debug,
29
hash::{Hash, Hasher},
30
iter, slice,
31
};
32
use graph::AnimationNodeType;
33
use prelude::AnimationCurveEvaluator;
34
35
use crate::{
36
graph::{AnimationGraphHandle, ThreadedAnimationGraphs},
37
prelude::EvaluatorId,
38
};
39
40
use bevy_app::{AnimationSystems, App, Plugin, PostUpdate};
41
use bevy_asset::{Asset, AssetApp, AssetEventSystems, Assets};
42
use bevy_ecs::{prelude::*, world::EntityMutExcept};
43
use bevy_math::FloatOrd;
44
use bevy_platform::{collections::HashMap, hash::NoOpHash};
45
use bevy_reflect::{prelude::ReflectDefault, Reflect, TypePath};
46
use bevy_time::Time;
47
use bevy_transform::TransformSystems;
48
use bevy_utils::{PreHashMap, PreHashMapExt, TypeIdMap};
49
use serde::{Deserialize, Serialize};
50
use thread_local::ThreadLocal;
51
use tracing::{trace, warn};
52
use uuid::Uuid;
53
54
/// The animation prelude.
55
///
56
/// This includes the most common types in this crate, re-exported for your convenience.
57
pub mod prelude {
58
#[doc(hidden)]
59
pub use crate::{
60
animatable::*, animation_curves::*, graph::*, transition::*, AnimationClip,
61
AnimationPlayer, AnimationPlugin, VariableCurve,
62
};
63
}
64
65
use crate::{
66
animation_curves::AnimationCurve,
67
graph::{AnimationGraph, AnimationGraphAssetLoader, AnimationNodeIndex},
68
transition::{advance_transitions, expire_completed_transitions},
69
};
70
use alloc::sync::Arc;
71
72
/// The [UUID namespace] of animation targets (e.g. bones).
73
///
74
/// [UUID namespace]: https://en.wikipedia.org/wiki/Universally_unique_identifier#Versions_3_and_5_(namespace_name-based)
75
pub static ANIMATION_TARGET_NAMESPACE: Uuid = Uuid::from_u128(0x3179f519d9274ff2b5966fd077023911);
76
77
/// Contains an [animation curve] which is used to animate a property of an entity.
78
///
79
/// [animation curve]: AnimationCurve
80
#[derive(Debug, TypePath)]
81
pub struct VariableCurve(pub Box<dyn AnimationCurve>);
82
83
impl Clone for VariableCurve {
84
fn clone(&self) -> Self {
85
Self(AnimationCurve::clone_value(&*self.0))
86
}
87
}
88
89
impl VariableCurve {
90
/// Create a new [`VariableCurve`] from an [animation curve].
91
///
92
/// [animation curve]: AnimationCurve
93
pub fn new(animation_curve: impl AnimationCurve) -> Self {
94
Self(Box::new(animation_curve))
95
}
96
}
97
98
/// A list of [`VariableCurve`]s and the [`AnimationTargetId`]s to which they
99
/// apply.
100
///
101
/// Because animation clips refer to targets by UUID, they can target any
102
/// entity with that ID.
103
#[derive(Asset, Reflect, Clone, Debug, Default)]
104
#[reflect(Clone, Default)]
105
pub struct AnimationClip {
106
// This field is ignored by reflection because AnimationCurves can contain things that are not reflect-able
107
#[reflect(ignore, clone)]
108
curves: AnimationCurves,
109
events: AnimationEvents,
110
duration: f32,
111
}
112
113
#[derive(Reflect, Debug, Clone)]
114
#[reflect(Clone)]
115
struct TimedAnimationEvent {
116
time: f32,
117
event: AnimationEventData,
118
}
119
120
#[derive(Reflect, Debug, Clone)]
121
#[reflect(Clone)]
122
struct AnimationEventData {
123
#[reflect(ignore, clone)]
124
trigger: AnimationEventFn,
125
}
126
127
impl AnimationEventData {
128
fn trigger(&self, commands: &mut Commands, entity: Entity, time: f32, weight: f32) {
129
(self.trigger.0)(commands, entity, time, weight);
130
}
131
}
132
133
#[derive(Reflect, Clone)]
134
#[reflect(opaque)]
135
#[reflect(Clone, Default, Debug)]
136
struct AnimationEventFn(Arc<dyn Fn(&mut Commands, Entity, f32, f32) + Send + Sync>);
137
138
impl Default for AnimationEventFn {
139
fn default() -> Self {
140
Self(Arc::new(|_commands, _entity, _time, _weight| {}))
141
}
142
}
143
144
impl Debug for AnimationEventFn {
145
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
146
f.debug_tuple("AnimationEventFn").finish()
147
}
148
}
149
150
#[derive(Reflect, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone)]
151
#[reflect(Clone)]
152
enum AnimationEventTarget {
153
Root,
154
Node(AnimationTargetId),
155
}
156
157
type AnimationEvents = HashMap<AnimationEventTarget, Vec<TimedAnimationEvent>>;
158
159
/// A mapping from [`AnimationTargetId`] (e.g. bone in a skinned mesh) to the
160
/// animation curves.
161
pub type AnimationCurves = HashMap<AnimationTargetId, Vec<VariableCurve>, NoOpHash>;
162
163
/// A component that identifies which parts of an [`AnimationClip`] asset can
164
/// be applied to an entity. Typically used alongside the
165
/// [`AnimatedBy`] component.
166
///
167
/// `AnimationTargetId` is implemented as a [UUID]. When importing an armature
168
/// or an animation clip, asset loaders typically use the full path name from
169
/// the armature to the bone to generate these UUIDs. The ID is unique to the
170
/// full path name and based only on the names. So, for example, any imported
171
/// armature with a bone at the root named `Hips` will assign the same
172
/// [`AnimationTargetId`] to its root bone. Likewise, any imported animation
173
/// clip that animates a root bone named `Hips` will reference the same
174
/// [`AnimationTargetId`]. Any animation is playable on any armature as long as
175
/// the bone names match, which allows for easy animation retargeting.
176
///
177
/// Note that asset loaders generally use the *full* path name to generate the
178
/// [`AnimationTargetId`]. Thus a bone named `Chest` directly connected to a
179
/// bone named `Hips` will have a different ID from a bone named `Chest` that's
180
/// connected to a bone named `Stomach`.
181
///
182
/// [UUID]: https://en.wikipedia.org/wiki/Universally_unique_identifier
183
#[derive(
184
Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Reflect, Debug, Serialize, Deserialize, Component,
185
)]
186
#[reflect(Component, Clone)]
187
pub struct AnimationTargetId(pub Uuid);
188
189
impl Hash for AnimationTargetId {
190
fn hash<H: Hasher>(&self, state: &mut H) {
191
let (hi, lo) = self.0.as_u64_pair();
192
state.write_u64(hi ^ lo);
193
}
194
}
195
196
/// A component that links an animated entity to an entity containing an
197
/// [`AnimationPlayer`]. Typically used alongside the [`AnimationTargetId`]
198
/// component - the linked `AnimationPlayer` plays [`AnimationClip`] assets, and
199
/// the `AnimationTargetId` identifies which curves in the `AnimationClip` will
200
/// affect the target entity.
201
///
202
/// By convention, asset loaders add [`AnimationTargetId`] components to the
203
/// descendants of an [`AnimationPlayer`], as well as to the [`AnimationPlayer`]
204
/// entity itself, but Bevy doesn't require this in any way. So, for example,
205
/// it's entirely possible for an [`AnimationPlayer`] to animate a target that
206
/// it isn't an ancestor of. If you add a new bone to or delete a bone from an
207
/// armature at runtime, you may want to update the [`AnimationTargetId`]
208
/// component as appropriate, as Bevy won't do this automatically.
209
///
210
/// Note that each entity can only be animated by one animation player at a
211
/// time. However, you can change [`AnimatedBy`] components at runtime and
212
/// link them to a different player.
213
#[derive(Clone, Copy, Component, Reflect, Debug)]
214
#[reflect(Component, Clone)]
215
pub struct AnimatedBy(#[entities] pub Entity);
216
217
impl AnimationClip {
218
#[inline]
219
/// [`VariableCurve`]s for each animation target. Indexed by the [`AnimationTargetId`].
220
pub fn curves(&self) -> &AnimationCurves {
221
&self.curves
222
}
223
224
#[inline]
225
/// Get mutable references of [`VariableCurve`]s for each animation target. Indexed by the [`AnimationTargetId`].
226
pub fn curves_mut(&mut self) -> &mut AnimationCurves {
227
&mut self.curves
228
}
229
230
/// Gets the curves for a single animation target.
231
///
232
/// Returns `None` if this clip doesn't animate the target.
233
#[inline]
234
pub fn curves_for_target(
235
&self,
236
target_id: AnimationTargetId,
237
) -> Option<&'_ Vec<VariableCurve>> {
238
self.curves.get(&target_id)
239
}
240
241
/// Gets mutable references of the curves for a single animation target.
242
///
243
/// Returns `None` if this clip doesn't animate the target.
244
#[inline]
245
pub fn curves_for_target_mut(
246
&mut self,
247
target_id: AnimationTargetId,
248
) -> Option<&'_ mut Vec<VariableCurve>> {
249
self.curves.get_mut(&target_id)
250
}
251
252
/// Duration of the clip, represented in seconds.
253
#[inline]
254
pub fn duration(&self) -> f32 {
255
self.duration
256
}
257
258
/// Set the duration of the clip in seconds.
259
#[inline]
260
pub fn set_duration(&mut self, duration_sec: f32) {
261
self.duration = duration_sec;
262
}
263
264
/// Adds an [`AnimationCurve`] that can target an entity with the given
265
/// [`AnimationTargetId`] component.
266
///
267
/// If the curve extends beyond the current duration of this clip, this
268
/// method lengthens this clip to include the entire time span that the
269
/// curve covers.
270
///
271
/// More specifically:
272
/// - This clip will be sampled on the interval `[0, duration]`.
273
/// - Each curve in the clip is sampled by first clamping the sample time to its [domain].
274
/// - Curves that extend forever never contribute to the duration.
275
///
276
/// For example, a curve with domain `[2, 5]` will extend the clip to cover `[0, 5]`
277
/// when added and will produce the same output on the entire interval `[0, 2]` because
278
/// these time values all get clamped to `2`.
279
///
280
/// By contrast, a curve with domain `[-10, ∞]` will never extend the clip duration when
281
/// added and will be sampled only on `[0, duration]`, ignoring all negative time values.
282
///
283
/// [domain]: AnimationCurve::domain
284
pub fn add_curve_to_target(
285
&mut self,
286
target_id: AnimationTargetId,
287
curve: impl AnimationCurve,
288
) {
289
// Update the duration of the animation by this curve duration if it's longer
290
let end = curve.domain().end();
291
if end.is_finite() {
292
self.duration = self.duration.max(end);
293
}
294
self.curves
295
.entry(target_id)
296
.or_default()
297
.push(VariableCurve::new(curve));
298
}
299
300
/// Like [`add_curve_to_target`], but adding a [`VariableCurve`] directly.
301
///
302
/// Under normal circumstances, that method is generally more convenient.
303
///
304
/// [`add_curve_to_target`]: AnimationClip::add_curve_to_target
305
pub fn add_variable_curve_to_target(
306
&mut self,
307
target_id: AnimationTargetId,
308
variable_curve: VariableCurve,
309
) {
310
let end = variable_curve.0.domain().end();
311
if end.is_finite() {
312
self.duration = self.duration.max(end);
313
}
314
self.curves
315
.entry(target_id)
316
.or_default()
317
.push(variable_curve);
318
}
319
320
/// Add an [`EntityEvent`] with no [`AnimationTargetId`].
321
///
322
/// The `event` will be cloned and triggered on the [`AnimationPlayer`] entity once the `time` (in seconds)
323
/// is reached in the animation.
324
///
325
/// See also [`add_event_to_target`](Self::add_event_to_target).
326
pub fn add_event(&mut self, time: f32, event: impl AnimationEvent) {
327
self.add_event_fn(
328
time,
329
move |commands: &mut Commands, target: Entity, _time: f32, _weight: f32| {
330
commands.trigger_with(event.clone(), AnimationEventTrigger { target });
331
},
332
);
333
}
334
335
/// Add an [`EntityEvent`] with an [`AnimationTargetId`].
336
///
337
/// The `event` will be cloned and triggered on the entity matching the target once the `time` (in seconds)
338
/// is reached in the animation.
339
///
340
/// Use [`add_event`](Self::add_event) instead if you don't have a specific target.
341
pub fn add_event_to_target(
342
&mut self,
343
target_id: AnimationTargetId,
344
time: f32,
345
event: impl AnimationEvent,
346
) {
347
self.add_event_fn_to_target(
348
target_id,
349
time,
350
move |commands: &mut Commands, target: Entity, _time: f32, _weight: f32| {
351
commands.trigger_with(event.clone(), AnimationEventTrigger { target });
352
},
353
);
354
}
355
356
/// Add an event function with no [`AnimationTargetId`] to this [`AnimationClip`].
357
///
358
/// The `func` will trigger on the [`AnimationPlayer`] entity once the `time` (in seconds)
359
/// is reached in the animation.
360
///
361
/// For a simpler [`EntityEvent`]-based alternative, see [`AnimationClip::add_event`].
362
/// See also [`add_event_to_target`](Self::add_event_to_target).
363
///
364
/// ```
365
/// # use bevy_animation::AnimationClip;
366
/// # let mut clip = AnimationClip::default();
367
/// clip.add_event_fn(1.0, |commands, entity, time, weight| {
368
/// println!("Animation event triggered {entity:#?} at time {time} with weight {weight}");
369
/// })
370
/// ```
371
pub fn add_event_fn(
372
&mut self,
373
time: f32,
374
func: impl Fn(&mut Commands, Entity, f32, f32) + Send + Sync + 'static,
375
) {
376
self.add_event_internal(AnimationEventTarget::Root, time, func);
377
}
378
379
/// Add an event function with an [`AnimationTargetId`].
380
///
381
/// The `func` will trigger on the entity matching the target once the `time` (in seconds)
382
/// is reached in the animation.
383
///
384
/// For a simpler [`EntityEvent`]-based alternative, see [`AnimationClip::add_event_to_target`].
385
/// Use [`add_event`](Self::add_event) instead if you don't have a specific target.
386
///
387
/// ```
388
/// # use bevy_animation::{AnimationClip, AnimationTargetId};
389
/// # let mut clip = AnimationClip::default();
390
/// clip.add_event_fn_to_target(AnimationTargetId::from_iter(["Arm", "Hand"]), 1.0, |commands, entity, time, weight| {
391
/// println!("Animation event triggered {entity:#?} at time {time} with weight {weight}");
392
/// })
393
/// ```
394
pub fn add_event_fn_to_target(
395
&mut self,
396
target_id: AnimationTargetId,
397
time: f32,
398
func: impl Fn(&mut Commands, Entity, f32, f32) + Send + Sync + 'static,
399
) {
400
self.add_event_internal(AnimationEventTarget::Node(target_id), time, func);
401
}
402
403
fn add_event_internal(
404
&mut self,
405
target: AnimationEventTarget,
406
time: f32,
407
trigger_fn: impl Fn(&mut Commands, Entity, f32, f32) + Send + Sync + 'static,
408
) {
409
self.duration = self.duration.max(time);
410
let triggers = self.events.entry(target).or_default();
411
match triggers.binary_search_by_key(&FloatOrd(time), |e| FloatOrd(e.time)) {
412
Ok(index) | Err(index) => triggers.insert(
413
index,
414
TimedAnimationEvent {
415
time,
416
event: AnimationEventData {
417
trigger: AnimationEventFn(Arc::new(trigger_fn)),
418
},
419
},
420
),
421
}
422
}
423
}
424
425
/// Repetition behavior of an animation.
426
#[derive(Reflect, Debug, PartialEq, Eq, Copy, Clone, Default)]
427
#[reflect(Clone, Default)]
428
pub enum RepeatAnimation {
429
/// The animation will finish after running once.
430
#[default]
431
Never,
432
/// The animation will finish after running "n" times.
433
Count(u32),
434
/// The animation will never finish.
435
Forever,
436
}
437
438
/// Why Bevy failed to evaluate an animation.
439
#[derive(Clone, Debug)]
440
pub enum AnimationEvaluationError {
441
/// The component to be animated isn't present on the animation target.
442
///
443
/// To fix this error, make sure the entity to be animated contains all
444
/// components that have animation curves.
445
ComponentNotPresent(TypeId),
446
447
/// The component to be animated was present, but the property on the
448
/// component wasn't present.
449
PropertyNotPresent(TypeId),
450
451
/// An internal error occurred in the implementation of
452
/// [`AnimationCurveEvaluator`].
453
///
454
/// You shouldn't ordinarily see this error unless you implemented
455
/// [`AnimationCurveEvaluator`] yourself. The contained [`TypeId`] is the ID
456
/// of the curve evaluator.
457
InconsistentEvaluatorImplementation(TypeId),
458
}
459
460
/// An animation that an [`AnimationPlayer`] is currently either playing or was
461
/// playing, but is presently paused.
462
///
463
/// A stopped animation is considered no longer active.
464
#[derive(Debug, Clone, Copy, Reflect)]
465
#[reflect(Clone, Default)]
466
pub struct ActiveAnimation {
467
/// The factor by which the weight from the [`AnimationGraph`] is multiplied.
468
weight: f32,
469
repeat: RepeatAnimation,
470
speed: f32,
471
/// Total time the animation has been played.
472
///
473
/// Note: Time does not increase when the animation is paused or after it has completed.
474
elapsed: f32,
475
/// The timestamp inside of the animation clip.
476
///
477
/// Note: This will always be in the range [0.0, animation clip duration]
478
seek_time: f32,
479
/// The `seek_time` of the previous tick, if any.
480
last_seek_time: Option<f32>,
481
/// Number of times the animation has completed.
482
/// If the animation is playing in reverse, this increments when the animation passes the start.
483
completions: u32,
484
/// `true` if the animation was completed at least once this tick.
485
just_completed: bool,
486
paused: bool,
487
}
488
489
impl Default for ActiveAnimation {
490
fn default() -> Self {
491
Self {
492
weight: 1.0,
493
repeat: RepeatAnimation::default(),
494
speed: 1.0,
495
elapsed: 0.0,
496
seek_time: 0.0,
497
last_seek_time: None,
498
completions: 0,
499
just_completed: false,
500
paused: false,
501
}
502
}
503
}
504
505
impl ActiveAnimation {
506
/// Check if the animation has finished, based on its repetition behavior and the number of times it has repeated.
507
///
508
/// Note: An animation with `RepeatAnimation::Forever` will never finish.
509
#[inline]
510
pub fn is_finished(&self) -> bool {
511
match self.repeat {
512
RepeatAnimation::Forever => false,
513
RepeatAnimation::Never => self.completions >= 1,
514
RepeatAnimation::Count(n) => self.completions >= n,
515
}
516
}
517
518
/// Update the animation given the delta time and the duration of the clip being played.
519
#[inline]
520
fn update(&mut self, delta: f32, clip_duration: f32) {
521
self.just_completed = false;
522
self.last_seek_time = Some(self.seek_time);
523
524
if self.is_finished() {
525
return;
526
}
527
528
self.elapsed += delta;
529
self.seek_time += delta * self.speed;
530
531
let over_time = self.speed > 0.0 && self.seek_time >= clip_duration;
532
let under_time = self.speed < 0.0 && self.seek_time < 0.0;
533
534
if over_time || under_time {
535
self.just_completed = true;
536
self.completions += 1;
537
538
if self.is_finished() {
539
return;
540
}
541
}
542
if self.seek_time >= clip_duration {
543
self.seek_time %= clip_duration;
544
}
545
// Note: assumes delta is never lower than -clip_duration
546
if self.seek_time < 0.0 {
547
self.seek_time += clip_duration;
548
}
549
}
550
551
/// Reset back to the initial state as if no time has elapsed.
552
pub fn replay(&mut self) {
553
self.just_completed = false;
554
self.completions = 0;
555
self.elapsed = 0.0;
556
self.last_seek_time = None;
557
self.seek_time = 0.0;
558
}
559
560
/// Returns the current weight of this animation.
561
pub fn weight(&self) -> f32 {
562
self.weight
563
}
564
565
/// Sets the weight of this animation.
566
pub fn set_weight(&mut self, weight: f32) -> &mut Self {
567
self.weight = weight;
568
self
569
}
570
571
/// Pause the animation.
572
pub fn pause(&mut self) -> &mut Self {
573
self.paused = true;
574
self
575
}
576
577
/// Unpause the animation.
578
pub fn resume(&mut self) -> &mut Self {
579
self.paused = false;
580
self
581
}
582
583
/// Returns true if this animation is currently paused.
584
///
585
/// Note that paused animations are still [`ActiveAnimation`]s.
586
#[inline]
587
pub fn is_paused(&self) -> bool {
588
self.paused
589
}
590
591
/// Sets the repeat mode for this playing animation.
592
pub fn set_repeat(&mut self, repeat: RepeatAnimation) -> &mut Self {
593
self.repeat = repeat;
594
self
595
}
596
597
/// Marks this animation as repeating forever.
598
pub fn repeat(&mut self) -> &mut Self {
599
self.set_repeat(RepeatAnimation::Forever)
600
}
601
602
/// Returns the repeat mode assigned to this active animation.
603
pub fn repeat_mode(&self) -> RepeatAnimation {
604
self.repeat
605
}
606
607
/// Returns the number of times this animation has completed.
608
pub fn completions(&self) -> u32 {
609
self.completions
610
}
611
612
/// Returns true if the animation is playing in reverse.
613
pub fn is_playback_reversed(&self) -> bool {
614
self.speed < 0.0
615
}
616
617
/// Returns the speed of the animation playback.
618
pub fn speed(&self) -> f32 {
619
self.speed
620
}
621
622
/// Sets the speed of the animation playback.
623
pub fn set_speed(&mut self, speed: f32) -> &mut Self {
624
self.speed = speed;
625
self
626
}
627
628
/// Returns the amount of time the animation has been playing.
629
pub fn elapsed(&self) -> f32 {
630
self.elapsed
631
}
632
633
/// Returns the seek time of the animation.
634
///
635
/// This is nonnegative and no more than the clip duration.
636
pub fn seek_time(&self) -> f32 {
637
self.seek_time
638
}
639
640
/// Seeks to a specific time in the animation.
641
///
642
/// This will not trigger events between the current time and `seek_time`.
643
/// Use [`seek_to`](Self::seek_to) if this is desired.
644
pub fn set_seek_time(&mut self, seek_time: f32) -> &mut Self {
645
self.last_seek_time = Some(seek_time);
646
self.seek_time = seek_time;
647
self
648
}
649
650
/// Seeks to a specific time in the animation.
651
///
652
/// Note that any events between the current time and `seek_time`
653
/// will be triggered on the next update.
654
/// Use [`set_seek_time`](Self::set_seek_time) if this is undesired.
655
pub fn seek_to(&mut self, seek_time: f32) -> &mut Self {
656
self.last_seek_time = Some(self.seek_time);
657
self.seek_time = seek_time;
658
self
659
}
660
661
/// Seeks to the beginning of the animation.
662
///
663
/// Note that any events between the current time and `0.0`
664
/// will be triggered on the next update.
665
/// Use [`set_seek_time`](Self::set_seek_time) if this is undesired.
666
pub fn rewind(&mut self) -> &mut Self {
667
self.last_seek_time = Some(self.seek_time);
668
self.seek_time = 0.0;
669
self
670
}
671
}
672
673
/// Animation controls.
674
///
675
/// Automatically added to any root animations of a scene when it is
676
/// spawned.
677
#[derive(Component, Default, Reflect)]
678
#[reflect(Component, Default, Clone)]
679
pub struct AnimationPlayer {
680
active_animations: HashMap<AnimationNodeIndex, ActiveAnimation>,
681
}
682
683
// This is needed since `#[derive(Clone)]` does not generate optimized `clone_from`.
684
impl Clone for AnimationPlayer {
685
fn clone(&self) -> Self {
686
Self {
687
active_animations: self.active_animations.clone(),
688
}
689
}
690
691
fn clone_from(&mut self, source: &Self) {
692
self.active_animations.clone_from(&source.active_animations);
693
}
694
}
695
696
/// Temporary data that the [`animate_targets`] system maintains.
697
#[derive(Default)]
698
pub struct AnimationEvaluationState {
699
/// Stores all [`AnimationCurveEvaluator`]s corresponding to properties that
700
/// we've seen so far.
701
///
702
/// This is a mapping from the id of an animation curve evaluator to
703
/// the animation curve evaluator itself.
704
///
705
/// For efficiency's sake, the [`AnimationCurveEvaluator`]s are cached from
706
/// frame to frame and animation target to animation target. Therefore,
707
/// there may be entries in this list corresponding to properties that the
708
/// current [`AnimationPlayer`] doesn't animate. To iterate only over the
709
/// properties that are currently being animated, consult the
710
/// [`Self::current_evaluators`] set.
711
evaluators: AnimationCurveEvaluators,
712
713
/// The set of [`AnimationCurveEvaluator`] types that the current
714
/// [`AnimationPlayer`] is animating.
715
///
716
/// This is built up as new curve evaluators are encountered during graph
717
/// traversal.
718
current_evaluators: CurrentEvaluators,
719
}
720
721
#[derive(Default)]
722
struct AnimationCurveEvaluators {
723
component_property_curve_evaluators:
724
PreHashMap<(TypeId, usize), Box<dyn AnimationCurveEvaluator>>,
725
type_id_curve_evaluators: TypeIdMap<Box<dyn AnimationCurveEvaluator>>,
726
}
727
728
impl AnimationCurveEvaluators {
729
#[inline]
730
pub(crate) fn get_mut(&mut self, id: EvaluatorId) -> Option<&mut dyn AnimationCurveEvaluator> {
731
match id {
732
EvaluatorId::ComponentField(component_property) => self
733
.component_property_curve_evaluators
734
.get_mut(component_property),
735
EvaluatorId::Type(type_id) => self.type_id_curve_evaluators.get_mut(&type_id),
736
}
737
.map(|e| &mut **e)
738
}
739
740
#[inline]
741
pub(crate) fn get_or_insert_with(
742
&mut self,
743
id: EvaluatorId,
744
func: impl FnOnce() -> Box<dyn AnimationCurveEvaluator>,
745
) -> &mut dyn AnimationCurveEvaluator {
746
match id {
747
EvaluatorId::ComponentField(component_property) => &mut **self
748
.component_property_curve_evaluators
749
.get_or_insert_with(component_property, func),
750
EvaluatorId::Type(type_id) => match self.type_id_curve_evaluators.entry(type_id) {
751
bevy_platform::collections::hash_map::Entry::Occupied(occupied_entry) => {
752
&mut **occupied_entry.into_mut()
753
}
754
bevy_platform::collections::hash_map::Entry::Vacant(vacant_entry) => {
755
&mut **vacant_entry.insert(func())
756
}
757
},
758
}
759
}
760
}
761
762
#[derive(Default)]
763
struct CurrentEvaluators {
764
component_properties: PreHashMap<(TypeId, usize), ()>,
765
type_ids: TypeIdMap<()>,
766
}
767
768
impl CurrentEvaluators {
769
pub(crate) fn keys(&self) -> impl Iterator<Item = EvaluatorId<'_>> {
770
self.component_properties
771
.keys()
772
.map(EvaluatorId::ComponentField)
773
.chain(self.type_ids.keys().copied().map(EvaluatorId::Type))
774
}
775
776
pub(crate) fn clear(
777
&mut self,
778
mut visit: impl FnMut(EvaluatorId) -> Result<(), AnimationEvaluationError>,
779
) -> Result<(), AnimationEvaluationError> {
780
for (key, _) in self.component_properties.drain() {
781
(visit)(EvaluatorId::ComponentField(&key))?;
782
}
783
784
for (key, _) in self.type_ids.drain() {
785
(visit)(EvaluatorId::Type(key))?;
786
}
787
788
Ok(())
789
}
790
791
#[inline]
792
pub(crate) fn insert(&mut self, id: EvaluatorId) {
793
match id {
794
EvaluatorId::ComponentField(component_property) => {
795
self.component_properties.insert(*component_property, ());
796
}
797
EvaluatorId::Type(type_id) => {
798
self.type_ids.insert(type_id, ());
799
}
800
}
801
}
802
}
803
804
impl AnimationPlayer {
805
/// Start playing an animation, restarting it if necessary.
806
pub fn start(&mut self, animation: AnimationNodeIndex) -> &mut ActiveAnimation {
807
let playing_animation = self.active_animations.entry(animation).or_default();
808
playing_animation.replay();
809
playing_animation
810
}
811
812
/// Start playing an animation, unless the requested animation is already playing.
813
pub fn play(&mut self, animation: AnimationNodeIndex) -> &mut ActiveAnimation {
814
self.active_animations.entry(animation).or_default()
815
}
816
817
/// Stops playing the given animation, removing it from the list of playing
818
/// animations.
819
pub fn stop(&mut self, animation: AnimationNodeIndex) -> &mut Self {
820
self.active_animations.remove(&animation);
821
self
822
}
823
824
/// Stops all currently-playing animations.
825
pub fn stop_all(&mut self) -> &mut Self {
826
self.active_animations.clear();
827
self
828
}
829
830
/// Iterates through all animations that this [`AnimationPlayer`] is
831
/// currently playing.
832
pub fn playing_animations(
833
&self,
834
) -> impl Iterator<Item = (&AnimationNodeIndex, &ActiveAnimation)> {
835
self.active_animations.iter()
836
}
837
838
/// Iterates through all animations that this [`AnimationPlayer`] is
839
/// currently playing, mutably.
840
pub fn playing_animations_mut(
841
&mut self,
842
) -> impl Iterator<Item = (&AnimationNodeIndex, &mut ActiveAnimation)> {
843
self.active_animations.iter_mut()
844
}
845
846
/// Returns true if the animation is currently playing or paused, or false
847
/// if the animation is stopped.
848
pub fn is_playing_animation(&self, animation: AnimationNodeIndex) -> bool {
849
self.active_animations.contains_key(&animation)
850
}
851
852
/// Check if all playing animations have finished, according to the repetition behavior.
853
pub fn all_finished(&self) -> bool {
854
self.active_animations
855
.values()
856
.all(ActiveAnimation::is_finished)
857
}
858
859
/// Check if all playing animations are paused.
860
#[doc(alias = "is_paused")]
861
pub fn all_paused(&self) -> bool {
862
self.active_animations
863
.values()
864
.all(ActiveAnimation::is_paused)
865
}
866
867
/// Pause all playing animations.
868
#[doc(alias = "pause")]
869
pub fn pause_all(&mut self) -> &mut Self {
870
for (_, playing_animation) in self.playing_animations_mut() {
871
playing_animation.pause();
872
}
873
self
874
}
875
876
/// Resume all active animations.
877
#[doc(alias = "resume")]
878
pub fn resume_all(&mut self) -> &mut Self {
879
for (_, playing_animation) in self.playing_animations_mut() {
880
playing_animation.resume();
881
}
882
self
883
}
884
885
/// Rewinds all active animations.
886
#[doc(alias = "rewind")]
887
pub fn rewind_all(&mut self) -> &mut Self {
888
for (_, playing_animation) in self.playing_animations_mut() {
889
playing_animation.rewind();
890
}
891
self
892
}
893
894
/// Multiplies the speed of all active animations by the given factor.
895
#[doc(alias = "set_speed")]
896
pub fn adjust_speeds(&mut self, factor: f32) -> &mut Self {
897
for (_, playing_animation) in self.playing_animations_mut() {
898
let new_speed = playing_animation.speed() * factor;
899
playing_animation.set_speed(new_speed);
900
}
901
self
902
}
903
904
/// Seeks all active animations forward or backward by the same amount.
905
///
906
/// To seek forward, pass a positive value; to seek negative, pass a
907
/// negative value. Values below 0.0 or beyond the end of the animation clip
908
/// are clamped appropriately.
909
#[doc(alias = "seek_to")]
910
pub fn seek_all_by(&mut self, amount: f32) -> &mut Self {
911
for (_, playing_animation) in self.playing_animations_mut() {
912
let new_time = playing_animation.seek_time();
913
playing_animation.seek_to(new_time + amount);
914
}
915
self
916
}
917
918
/// Returns the [`ActiveAnimation`] associated with the given animation
919
/// node if it's currently playing.
920
///
921
/// If the animation isn't currently active, returns `None`.
922
pub fn animation(&self, animation: AnimationNodeIndex) -> Option<&ActiveAnimation> {
923
self.active_animations.get(&animation)
924
}
925
926
/// Returns a mutable reference to the [`ActiveAnimation`] associated with
927
/// the given animation node if it's currently active.
928
///
929
/// If the animation isn't currently active, returns `None`.
930
pub fn animation_mut(&mut self, animation: AnimationNodeIndex) -> Option<&mut ActiveAnimation> {
931
self.active_animations.get_mut(&animation)
932
}
933
}
934
935
/// A system that triggers untargeted animation events for the currently-playing animations.
936
fn trigger_untargeted_animation_events(
937
mut commands: Commands,
938
clips: Res<Assets<AnimationClip>>,
939
graphs: Res<Assets<AnimationGraph>>,
940
players: Query<(Entity, &AnimationPlayer, &AnimationGraphHandle)>,
941
) {
942
for (entity, player, graph_id) in &players {
943
// The graph might not have loaded yet. Safely bail.
944
let Some(graph) = graphs.get(graph_id) else {
945
return;
946
};
947
948
for (index, active_animation) in player.active_animations.iter() {
949
if active_animation.paused {
950
continue;
951
}
952
953
let Some(clip) = graph
954
.get(*index)
955
.and_then(|node| match &node.node_type {
956
AnimationNodeType::Clip(handle) => Some(handle),
957
AnimationNodeType::Blend | AnimationNodeType::Add => None,
958
})
959
.and_then(|id| clips.get(id))
960
else {
961
continue;
962
};
963
964
let Some(triggered_events) =
965
TriggeredEvents::from_animation(AnimationEventTarget::Root, clip, active_animation)
966
else {
967
continue;
968
};
969
970
for TimedAnimationEvent { time, event } in triggered_events.iter() {
971
event.trigger(&mut commands, entity, *time, active_animation.weight);
972
}
973
}
974
}
975
}
976
977
/// A system that advances the time for all playing animations.
978
pub fn advance_animations(
979
time: Res<Time>,
980
animation_clips: Res<Assets<AnimationClip>>,
981
animation_graphs: Res<Assets<AnimationGraph>>,
982
mut players: Query<(&mut AnimationPlayer, &AnimationGraphHandle)>,
983
) {
984
let delta_seconds = time.delta_secs();
985
players
986
.par_iter_mut()
987
.for_each(|(mut player, graph_handle)| {
988
let Some(animation_graph) = animation_graphs.get(graph_handle) else {
989
return;
990
};
991
992
// Tick animations, and schedule them.
993
994
let AnimationPlayer {
995
ref mut active_animations,
996
..
997
} = *player;
998
999
for node_index in animation_graph.graph.node_indices() {
1000
let node = &animation_graph[node_index];
1001
1002
if let Some(active_animation) = active_animations.get_mut(&node_index) {
1003
// Tick the animation if necessary.
1004
if !active_animation.paused
1005
&& let AnimationNodeType::Clip(ref clip_handle) = node.node_type
1006
&& let Some(clip) = animation_clips.get(clip_handle)
1007
{
1008
active_animation.update(delta_seconds, clip.duration);
1009
}
1010
}
1011
}
1012
});
1013
}
1014
1015
/// A type alias for [`EntityMutExcept`] as used in animation.
1016
pub type AnimationEntityMut<'w, 's> = EntityMutExcept<
1017
'w,
1018
's,
1019
(
1020
AnimationTargetId,
1021
AnimatedBy,
1022
AnimationPlayer,
1023
AnimationGraphHandle,
1024
),
1025
>;
1026
1027
/// A system that modifies animation targets (e.g. bones in a skinned mesh)
1028
/// according to the currently-playing animations.
1029
pub fn animate_targets(
1030
par_commands: ParallelCommands,
1031
clips: Res<Assets<AnimationClip>>,
1032
graphs: Res<Assets<AnimationGraph>>,
1033
threaded_animation_graphs: Res<ThreadedAnimationGraphs>,
1034
players: Query<(&AnimationPlayer, &AnimationGraphHandle)>,
1035
mut targets: Query<(Entity, &AnimationTargetId, &AnimatedBy, AnimationEntityMut)>,
1036
animation_evaluation_state: Local<ThreadLocal<RefCell<AnimationEvaluationState>>>,
1037
) {
1038
// Evaluate all animation targets in parallel.
1039
targets
1040
.par_iter_mut()
1041
.for_each(|(entity, &target_id, &AnimatedBy(player_id), entity_mut)| {
1042
let (animation_player, animation_graph_id) =
1043
if let Ok((player, graph_handle)) = players.get(player_id) {
1044
(player, graph_handle.id())
1045
} else {
1046
trace!(
1047
"Either an animation player {} or a graph was missing for the target \
1048
entity {} ({:?}); no animations will play this frame",
1049
player_id,
1050
entity_mut.id(),
1051
entity_mut.get::<Name>(),
1052
);
1053
return;
1054
};
1055
1056
// The graph might not have loaded yet. Safely bail.
1057
let Some(animation_graph) = graphs.get(animation_graph_id) else {
1058
return;
1059
};
1060
1061
let Some(threaded_animation_graph) =
1062
threaded_animation_graphs.0.get(&animation_graph_id)
1063
else {
1064
return;
1065
};
1066
1067
// Determine which mask groups this animation target belongs to.
1068
let target_mask = animation_graph
1069
.mask_groups
1070
.get(&target_id)
1071
.cloned()
1072
.unwrap_or_default();
1073
1074
let mut evaluation_state = animation_evaluation_state.get_or_default().borrow_mut();
1075
let evaluation_state = &mut *evaluation_state;
1076
1077
// Evaluate the graph.
1078
for &animation_graph_node_index in threaded_animation_graph.threaded_graph.iter() {
1079
let Some(animation_graph_node) = animation_graph.get(animation_graph_node_index)
1080
else {
1081
continue;
1082
};
1083
1084
match animation_graph_node.node_type {
1085
AnimationNodeType::Blend => {
1086
// This is a blend node.
1087
for edge_index in threaded_animation_graph.sorted_edge_ranges
1088
[animation_graph_node_index.index()]
1089
.clone()
1090
{
1091
if let Err(err) = evaluation_state.blend_all(
1092
threaded_animation_graph.sorted_edges[edge_index as usize],
1093
) {
1094
warn!("Failed to blend animation: {:?}", err);
1095
}
1096
}
1097
1098
if let Err(err) = evaluation_state.push_blend_register_all(
1099
animation_graph_node.weight,
1100
animation_graph_node_index,
1101
) {
1102
warn!("Animation blending failed: {:?}", err);
1103
}
1104
}
1105
1106
AnimationNodeType::Add => {
1107
// This is an additive blend node.
1108
for edge_index in threaded_animation_graph.sorted_edge_ranges
1109
[animation_graph_node_index.index()]
1110
.clone()
1111
{
1112
if let Err(err) = evaluation_state
1113
.add_all(threaded_animation_graph.sorted_edges[edge_index as usize])
1114
{
1115
warn!("Failed to blend animation: {:?}", err);
1116
}
1117
}
1118
1119
if let Err(err) = evaluation_state.push_blend_register_all(
1120
animation_graph_node.weight,
1121
animation_graph_node_index,
1122
) {
1123
warn!("Animation blending failed: {:?}", err);
1124
}
1125
}
1126
1127
AnimationNodeType::Clip(ref animation_clip_handle) => {
1128
// This is a clip node.
1129
let Some(active_animation) = animation_player
1130
.active_animations
1131
.get(&animation_graph_node_index)
1132
else {
1133
continue;
1134
};
1135
1136
// If the weight is zero or the current animation target is
1137
// masked out, stop here.
1138
if active_animation.weight == 0.0
1139
|| (target_mask
1140
& threaded_animation_graph.computed_masks
1141
[animation_graph_node_index.index()])
1142
!= 0
1143
{
1144
continue;
1145
}
1146
1147
let Some(clip) = clips.get(animation_clip_handle) else {
1148
continue;
1149
};
1150
1151
if !active_animation.paused {
1152
// Trigger all animation events that occurred this tick, if any.
1153
if let Some(triggered_events) = TriggeredEvents::from_animation(
1154
AnimationEventTarget::Node(target_id),
1155
clip,
1156
active_animation,
1157
) && !triggered_events.is_empty()
1158
{
1159
par_commands.command_scope(move |mut commands| {
1160
for TimedAnimationEvent { time, event } in
1161
triggered_events.iter()
1162
{
1163
event.trigger(
1164
&mut commands,
1165
entity,
1166
*time,
1167
active_animation.weight,
1168
);
1169
}
1170
});
1171
}
1172
}
1173
1174
let Some(curves) = clip.curves_for_target(target_id) else {
1175
continue;
1176
};
1177
1178
let weight = active_animation.weight * animation_graph_node.weight;
1179
let seek_time = active_animation.seek_time;
1180
1181
for curve in curves {
1182
// Fetch the curve evaluator. Curve evaluator types
1183
// are unique to each property, but shared among all
1184
// curve types. For example, given two curve types A
1185
// and B, `RotationCurve<A>` and `RotationCurve<B>`
1186
// will both yield a `RotationCurveEvaluator` and
1187
// therefore will share the same evaluator in this
1188
// table.
1189
let curve_evaluator_id = (*curve.0).evaluator_id();
1190
let curve_evaluator = evaluation_state
1191
.evaluators
1192
.get_or_insert_with(curve_evaluator_id.clone(), || {
1193
curve.0.create_evaluator()
1194
});
1195
1196
evaluation_state
1197
.current_evaluators
1198
.insert(curve_evaluator_id);
1199
1200
if let Err(err) = AnimationCurve::apply(
1201
&*curve.0,
1202
curve_evaluator,
1203
seek_time,
1204
weight,
1205
animation_graph_node_index,
1206
) {
1207
warn!("Animation application failed: {:?}", err);
1208
}
1209
}
1210
}
1211
}
1212
}
1213
1214
if let Err(err) = evaluation_state.commit_all(entity_mut) {
1215
warn!("Animation application failed: {:?}", err);
1216
}
1217
});
1218
}
1219
1220
/// Adds animation support to an app
1221
#[derive(Default)]
1222
pub struct AnimationPlugin;
1223
1224
impl Plugin for AnimationPlugin {
1225
fn build(&self, app: &mut App) {
1226
app.init_asset::<AnimationClip>()
1227
.init_asset::<AnimationGraph>()
1228
.init_asset_loader::<AnimationGraphAssetLoader>()
1229
.register_asset_reflect::<AnimationClip>()
1230
.register_asset_reflect::<AnimationGraph>()
1231
.init_resource::<ThreadedAnimationGraphs>()
1232
.add_systems(
1233
PostUpdate,
1234
(
1235
graph::thread_animation_graphs.before(AssetEventSystems),
1236
advance_transitions,
1237
advance_animations,
1238
// TODO: `animate_targets` can animate anything, so
1239
// ambiguity testing currently considers it ambiguous with
1240
// every other system in `PostUpdate`. We may want to move
1241
// it to its own system set after `Update` but before
1242
// `PostUpdate`. For now, we just disable ambiguity testing
1243
// for this system.
1244
#[cfg(feature = "bevy_mesh")]
1245
animate_targets
1246
.before(bevy_mesh::InheritWeightSystems)
1247
.ambiguous_with_all(),
1248
#[cfg(not(feature = "bevy_mesh"))]
1249
animate_targets.ambiguous_with_all(),
1250
trigger_untargeted_animation_events,
1251
expire_completed_transitions,
1252
)
1253
.chain()
1254
.in_set(AnimationSystems)
1255
.before(TransformSystems::Propagate),
1256
);
1257
}
1258
}
1259
1260
impl AnimationTargetId {
1261
/// Creates a new [`AnimationTargetId`] by hashing a list of names.
1262
///
1263
/// Typically, this will be the path from the animation root to the
1264
/// animation target (e.g. bone) that is to be animated.
1265
pub fn from_names<'a>(names: impl Iterator<Item = &'a Name>) -> Self {
1266
let mut blake3 = blake3::Hasher::new();
1267
blake3.update(ANIMATION_TARGET_NAMESPACE.as_bytes());
1268
for name in names {
1269
blake3.update(name.as_bytes());
1270
}
1271
let hash = blake3.finalize().as_bytes()[0..16].try_into().unwrap();
1272
Self(*uuid::Builder::from_sha1_bytes(hash).as_uuid())
1273
}
1274
1275
/// Creates a new [`AnimationTargetId`] by hashing a single name.
1276
pub fn from_name(name: &Name) -> Self {
1277
Self::from_names(iter::once(name))
1278
}
1279
}
1280
1281
impl<T: AsRef<str>> FromIterator<T> for AnimationTargetId {
1282
/// Creates a new [`AnimationTargetId`] by hashing a list of strings.
1283
///
1284
/// Typically, this will be the path from the animation root to the
1285
/// animation target (e.g. bone) that is to be animated.
1286
fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
1287
let mut blake3 = blake3::Hasher::new();
1288
blake3.update(ANIMATION_TARGET_NAMESPACE.as_bytes());
1289
for str in iter {
1290
blake3.update(str.as_ref().as_bytes());
1291
}
1292
let hash = blake3.finalize().as_bytes()[0..16].try_into().unwrap();
1293
Self(*uuid::Builder::from_sha1_bytes(hash).as_uuid())
1294
}
1295
}
1296
1297
impl From<&Name> for AnimationTargetId {
1298
fn from(name: &Name) -> Self {
1299
AnimationTargetId::from_name(name)
1300
}
1301
}
1302
1303
impl AnimationEvaluationState {
1304
/// Calls [`AnimationCurveEvaluator::blend`] on all curve evaluator types
1305
/// that we've been building up for a single target.
1306
///
1307
/// The given `node_index` is the node that we're evaluating.
1308
fn blend_all(
1309
&mut self,
1310
node_index: AnimationNodeIndex,
1311
) -> Result<(), AnimationEvaluationError> {
1312
for curve_evaluator_type in self.current_evaluators.keys() {
1313
self.evaluators
1314
.get_mut(curve_evaluator_type)
1315
.unwrap()
1316
.blend(node_index)?;
1317
}
1318
Ok(())
1319
}
1320
1321
/// Calls [`AnimationCurveEvaluator::add`] on all curve evaluator types
1322
/// that we've been building up for a single target.
1323
///
1324
/// The given `node_index` is the node that we're evaluating.
1325
fn add_all(&mut self, node_index: AnimationNodeIndex) -> Result<(), AnimationEvaluationError> {
1326
for curve_evaluator_type in self.current_evaluators.keys() {
1327
self.evaluators
1328
.get_mut(curve_evaluator_type)
1329
.unwrap()
1330
.add(node_index)?;
1331
}
1332
Ok(())
1333
}
1334
1335
/// Calls [`AnimationCurveEvaluator::push_blend_register`] on all curve
1336
/// evaluator types that we've been building up for a single target.
1337
///
1338
/// The `weight` parameter is the weight that should be pushed onto the
1339
/// stack, while the `node_index` parameter is the node that we're
1340
/// evaluating.
1341
fn push_blend_register_all(
1342
&mut self,
1343
weight: f32,
1344
node_index: AnimationNodeIndex,
1345
) -> Result<(), AnimationEvaluationError> {
1346
for curve_evaluator_type in self.current_evaluators.keys() {
1347
self.evaluators
1348
.get_mut(curve_evaluator_type)
1349
.unwrap()
1350
.push_blend_register(weight, node_index)?;
1351
}
1352
Ok(())
1353
}
1354
1355
/// Calls [`AnimationCurveEvaluator::commit`] on all curve evaluator types
1356
/// that we've been building up for a single target.
1357
///
1358
/// This is the call that actually writes the computed values into the
1359
/// components being animated.
1360
fn commit_all(
1361
&mut self,
1362
mut entity_mut: AnimationEntityMut,
1363
) -> Result<(), AnimationEvaluationError> {
1364
self.current_evaluators.clear(|id| {
1365
self.evaluators
1366
.get_mut(id)
1367
.unwrap()
1368
.commit(entity_mut.reborrow())
1369
})
1370
}
1371
}
1372
1373
/// All the events from an [`AnimationClip`] that occurred this tick.
1374
#[derive(Debug, Clone)]
1375
struct TriggeredEvents<'a> {
1376
direction: TriggeredEventsDir,
1377
lower: &'a [TimedAnimationEvent],
1378
upper: &'a [TimedAnimationEvent],
1379
}
1380
1381
impl<'a> TriggeredEvents<'a> {
1382
fn from_animation(
1383
target: AnimationEventTarget,
1384
clip: &'a AnimationClip,
1385
active_animation: &ActiveAnimation,
1386
) -> Option<Self> {
1387
let events = clip.events.get(&target)?;
1388
let reverse = active_animation.is_playback_reversed();
1389
let is_finished = active_animation.is_finished();
1390
1391
// Return early if the animation have finished on a previous tick.
1392
if is_finished && !active_animation.just_completed {
1393
return None;
1394
}
1395
1396
// The animation completed this tick, while still playing.
1397
let looping = active_animation.just_completed && !is_finished;
1398
let direction = match (reverse, looping) {
1399
(false, false) => TriggeredEventsDir::Forward,
1400
(false, true) => TriggeredEventsDir::ForwardLooping,
1401
(true, false) => TriggeredEventsDir::Reverse,
1402
(true, true) => TriggeredEventsDir::ReverseLooping,
1403
};
1404
1405
let last_time = active_animation.last_seek_time?;
1406
let this_time = active_animation.seek_time;
1407
1408
let (lower, upper) = match direction {
1409
// Return all events where last_time <= event.time < this_time.
1410
TriggeredEventsDir::Forward => {
1411
let start = events.partition_point(|event| event.time < last_time);
1412
// The animation finished this tick, return any remaining events.
1413
if is_finished {
1414
(&events[start..], &events[0..0])
1415
} else {
1416
let end = events.partition_point(|event| event.time < this_time);
1417
(&events[start..end], &events[0..0])
1418
}
1419
}
1420
// Return all events where this_time < event.time <= last_time.
1421
TriggeredEventsDir::Reverse => {
1422
let end = events.partition_point(|event| event.time <= last_time);
1423
// The animation finished, return any remaining events.
1424
if is_finished {
1425
(&events[..end], &events[0..0])
1426
} else {
1427
let start = events.partition_point(|event| event.time <= this_time);
1428
(&events[start..end], &events[0..0])
1429
}
1430
}
1431
// The animation is looping this tick and we have to return events where
1432
// either last_tick <= event.time or event.time < this_tick.
1433
TriggeredEventsDir::ForwardLooping => {
1434
let upper_start = events.partition_point(|event| event.time < last_time);
1435
let lower_end = events.partition_point(|event| event.time < this_time);
1436
1437
let upper = &events[upper_start..];
1438
let lower = &events[..lower_end];
1439
(lower, upper)
1440
}
1441
// The animation is looping this tick and we have to return events where
1442
// either last_tick >= event.time or event.time > this_tick.
1443
TriggeredEventsDir::ReverseLooping => {
1444
let lower_end = events.partition_point(|event| event.time <= last_time);
1445
let upper_start = events.partition_point(|event| event.time <= this_time);
1446
1447
let upper = &events[upper_start..];
1448
let lower = &events[..lower_end];
1449
(lower, upper)
1450
}
1451
};
1452
Some(Self {
1453
direction,
1454
lower,
1455
upper,
1456
})
1457
}
1458
1459
fn is_empty(&self) -> bool {
1460
self.lower.is_empty() && self.upper.is_empty()
1461
}
1462
1463
fn iter(&self) -> TriggeredEventsIter<'_> {
1464
match self.direction {
1465
TriggeredEventsDir::Forward => TriggeredEventsIter::Forward(self.lower.iter()),
1466
TriggeredEventsDir::Reverse => TriggeredEventsIter::Reverse(self.lower.iter().rev()),
1467
TriggeredEventsDir::ForwardLooping => TriggeredEventsIter::ForwardLooping {
1468
upper: self.upper.iter(),
1469
lower: self.lower.iter(),
1470
},
1471
TriggeredEventsDir::ReverseLooping => TriggeredEventsIter::ReverseLooping {
1472
lower: self.lower.iter().rev(),
1473
upper: self.upper.iter().rev(),
1474
},
1475
}
1476
}
1477
}
1478
1479
#[derive(Debug, Clone, Copy)]
1480
enum TriggeredEventsDir {
1481
/// The animation is playing normally
1482
Forward,
1483
/// The animation is playing in reverse
1484
Reverse,
1485
/// The animation is looping this tick
1486
ForwardLooping,
1487
/// The animation playing in reverse and looping this tick
1488
ReverseLooping,
1489
}
1490
1491
#[derive(Debug, Clone)]
1492
enum TriggeredEventsIter<'a> {
1493
Forward(slice::Iter<'a, TimedAnimationEvent>),
1494
Reverse(iter::Rev<slice::Iter<'a, TimedAnimationEvent>>),
1495
ForwardLooping {
1496
upper: slice::Iter<'a, TimedAnimationEvent>,
1497
lower: slice::Iter<'a, TimedAnimationEvent>,
1498
},
1499
ReverseLooping {
1500
lower: iter::Rev<slice::Iter<'a, TimedAnimationEvent>>,
1501
upper: iter::Rev<slice::Iter<'a, TimedAnimationEvent>>,
1502
},
1503
}
1504
1505
impl<'a> Iterator for TriggeredEventsIter<'a> {
1506
type Item = &'a TimedAnimationEvent;
1507
1508
fn next(&mut self) -> Option<Self::Item> {
1509
match self {
1510
TriggeredEventsIter::Forward(iter) => iter.next(),
1511
TriggeredEventsIter::Reverse(rev) => rev.next(),
1512
TriggeredEventsIter::ForwardLooping { upper, lower } => {
1513
upper.next().or_else(|| lower.next())
1514
}
1515
TriggeredEventsIter::ReverseLooping { lower, upper } => {
1516
lower.next().or_else(|| upper.next())
1517
}
1518
}
1519
}
1520
}
1521
1522
#[cfg(test)]
1523
mod tests {
1524
use crate as bevy_animation;
1525
use bevy_reflect::map::{DynamicMap, Map};
1526
1527
use super::*;
1528
1529
#[derive(AnimationEvent, Reflect, Clone)]
1530
struct A;
1531
1532
#[track_caller]
1533
fn assert_triggered_events_with(
1534
active_animation: &ActiveAnimation,
1535
clip: &AnimationClip,
1536
expected: impl Into<Vec<f32>>,
1537
) {
1538
let Some(events) =
1539
TriggeredEvents::from_animation(AnimationEventTarget::Root, clip, active_animation)
1540
else {
1541
assert_eq!(expected.into(), Vec::<f32>::new());
1542
return;
1543
};
1544
let got: Vec<_> = events.iter().map(|t| t.time).collect();
1545
assert_eq!(
1546
expected.into(),
1547
got,
1548
"\n{events:#?}\nlast_time: {:?}\nthis_time:{}",
1549
active_animation.last_seek_time,
1550
active_animation.seek_time
1551
);
1552
}
1553
1554
#[test]
1555
fn test_multiple_events_triggers() {
1556
let mut active_animation = ActiveAnimation {
1557
repeat: RepeatAnimation::Forever,
1558
..Default::default()
1559
};
1560
let mut clip = AnimationClip {
1561
duration: 1.0,
1562
..Default::default()
1563
};
1564
clip.add_event(0.5, A);
1565
clip.add_event(0.5, A);
1566
clip.add_event(0.5, A);
1567
1568
assert_triggered_events_with(&active_animation, &clip, []);
1569
active_animation.update(0.8, clip.duration); // 0.0 : 0.8
1570
assert_triggered_events_with(&active_animation, &clip, [0.5, 0.5, 0.5]);
1571
1572
clip.add_event(1.0, A);
1573
clip.add_event(0.0, A);
1574
clip.add_event(1.0, A);
1575
clip.add_event(0.0, A);
1576
1577
active_animation.update(0.4, clip.duration); // 0.8 : 0.2
1578
assert_triggered_events_with(&active_animation, &clip, [1.0, 1.0, 0.0, 0.0]);
1579
}
1580
1581
#[test]
1582
fn test_events_triggers() {
1583
let mut active_animation = ActiveAnimation::default();
1584
let mut clip = AnimationClip::default();
1585
clip.add_event(0.2, A);
1586
clip.add_event(0.0, A);
1587
assert_eq!(0.2, clip.duration);
1588
1589
assert_triggered_events_with(&active_animation, &clip, []);
1590
active_animation.update(0.1, clip.duration); // 0.0 : 0.1
1591
assert_triggered_events_with(&active_animation, &clip, [0.0]);
1592
active_animation.update(0.1, clip.duration); // 0.1 : 0.2
1593
assert_triggered_events_with(&active_animation, &clip, [0.2]);
1594
active_animation.update(0.1, clip.duration); // 0.2 : 0.2
1595
assert_triggered_events_with(&active_animation, &clip, []);
1596
active_animation.update(0.1, clip.duration); // 0.2 : 0.2
1597
assert_triggered_events_with(&active_animation, &clip, []);
1598
1599
active_animation.speed = -1.0;
1600
active_animation.completions = 0;
1601
assert_triggered_events_with(&active_animation, &clip, []);
1602
active_animation.update(0.1, clip.duration); // 0.2 : 0.1
1603
assert_triggered_events_with(&active_animation, &clip, [0.2]);
1604
active_animation.update(0.1, clip.duration); // 0.1 : 0.0
1605
assert_triggered_events_with(&active_animation, &clip, []);
1606
active_animation.update(0.1, clip.duration); // 0.0 : 0.0
1607
assert_triggered_events_with(&active_animation, &clip, [0.0]);
1608
active_animation.update(0.1, clip.duration); // 0.0 : 0.0
1609
assert_triggered_events_with(&active_animation, &clip, []);
1610
}
1611
1612
#[test]
1613
fn test_events_triggers_looping() {
1614
let mut active_animation = ActiveAnimation {
1615
repeat: RepeatAnimation::Forever,
1616
..Default::default()
1617
};
1618
let mut clip = AnimationClip::default();
1619
clip.add_event(0.3, A);
1620
clip.add_event(0.0, A);
1621
clip.add_event(0.2, A);
1622
assert_eq!(0.3, clip.duration);
1623
1624
assert_triggered_events_with(&active_animation, &clip, []);
1625
active_animation.update(0.1, clip.duration); // 0.0 : 0.1
1626
assert_triggered_events_with(&active_animation, &clip, [0.0]);
1627
active_animation.update(0.1, clip.duration); // 0.1 : 0.2
1628
assert_triggered_events_with(&active_animation, &clip, []);
1629
active_animation.update(0.1, clip.duration); // 0.2 : 0.3
1630
assert_triggered_events_with(&active_animation, &clip, [0.2, 0.3]);
1631
active_animation.update(0.1, clip.duration); // 0.3 : 0.1
1632
assert_triggered_events_with(&active_animation, &clip, [0.0]);
1633
active_animation.update(0.1, clip.duration); // 0.1 : 0.2
1634
assert_triggered_events_with(&active_animation, &clip, []);
1635
1636
active_animation.speed = -1.0;
1637
active_animation.update(0.1, clip.duration); // 0.2 : 0.1
1638
assert_triggered_events_with(&active_animation, &clip, [0.2]);
1639
active_animation.update(0.1, clip.duration); // 0.1 : 0.0
1640
assert_triggered_events_with(&active_animation, &clip, []);
1641
active_animation.update(0.1, clip.duration); // 0.0 : 0.2
1642
assert_triggered_events_with(&active_animation, &clip, [0.0, 0.3]);
1643
active_animation.update(0.1, clip.duration); // 0.2 : 0.1
1644
assert_triggered_events_with(&active_animation, &clip, [0.2]);
1645
active_animation.update(0.1, clip.duration); // 0.1 : 0.0
1646
assert_triggered_events_with(&active_animation, &clip, []);
1647
1648
active_animation.replay();
1649
active_animation.update(clip.duration, clip.duration); // 0.0 : 0.0
1650
assert_triggered_events_with(&active_animation, &clip, [0.0, 0.3, 0.2]);
1651
1652
active_animation.replay();
1653
active_animation.seek_time = clip.duration;
1654
active_animation.last_seek_time = Some(clip.duration);
1655
active_animation.update(clip.duration, clip.duration); // 0.3 : 0.0
1656
assert_triggered_events_with(&active_animation, &clip, [0.3, 0.2]);
1657
}
1658
1659
#[test]
1660
fn test_animation_node_index_as_key_of_dynamic_map() {
1661
let mut map = DynamicMap::default();
1662
map.insert_boxed(
1663
Box::new(AnimationNodeIndex::new(0)),
1664
Box::new(ActiveAnimation::default()),
1665
);
1666
}
1667
}
1668
1669