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