bevy_animation/
lib.rs

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