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