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
8extern 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
49pub 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
67pub static ANIMATION_TARGET_NAMESPACE: Uuid = Uuid::from_u128(0x3179f519d9274ff2b5966fd077023911);
71
72#[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 pub fn new(animation_curve: impl AnimationCurve) -> Self {
89 Self(Box::new(animation_curve))
90 }
91}
92
93#[derive(Asset, Reflect, Clone, Debug, Default)]
99#[reflect(Clone, Default)]
100pub struct AnimationClip {
101 #[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
154pub type AnimationCurves = HashMap<AnimationTargetId, Vec<VariableCurve>, NoOpHash>;
157
158#[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#[derive(Clone, Copy, Component, Reflect)]
212#[reflect(Component, Clone)]
213pub struct AnimationTarget {
214 pub id: AnimationTargetId,
218
219 #[entities]
221 pub player: Entity,
222}
223
224impl AnimationClip {
225 #[inline]
226 pub fn curves(&self) -> &AnimationCurves {
228 &self.curves
229 }
230
231 #[inline]
232 pub fn curves_mut(&mut self) -> &mut AnimationCurves {
234 &mut self.curves
235 }
236
237 #[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 #[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 #[inline]
261 pub fn duration(&self) -> f32 {
262 self.duration
263 }
264
265 #[inline]
267 pub fn set_duration(&mut self, duration_sec: f32) {
268 self.duration = duration_sec;
269 }
270
271 pub fn add_curve_to_target(
292 &mut self,
293 target_id: AnimationTargetId,
294 curve: impl AnimationCurve,
295 ) {
296 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 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 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 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 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 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#[derive(Reflect, Debug, PartialEq, Eq, Copy, Clone, Default)]
434#[reflect(Clone, Default)]
435pub enum RepeatAnimation {
436 #[default]
438 Never,
439 Count(u32),
441 Forever,
443}
444
445#[derive(Clone, Debug)]
447pub enum AnimationEvaluationError {
448 ComponentNotPresent(TypeId),
453
454 PropertyNotPresent(TypeId),
457
458 InconsistentEvaluatorImplementation(TypeId),
465}
466
467#[derive(Debug, Clone, Copy, Reflect)]
472#[reflect(Clone, Default)]
473pub struct ActiveAnimation {
474 weight: f32,
476 repeat: RepeatAnimation,
477 speed: f32,
478 elapsed: f32,
482 seek_time: f32,
486 last_seek_time: Option<f32>,
488 completions: u32,
491 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 #[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 #[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 if self.seek_time < 0.0 {
554 self.seek_time += clip_duration;
555 }
556 }
557
558 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 pub fn weight(&self) -> f32 {
569 self.weight
570 }
571
572 pub fn set_weight(&mut self, weight: f32) -> &mut Self {
574 self.weight = weight;
575 self
576 }
577
578 pub fn pause(&mut self) -> &mut Self {
580 self.paused = true;
581 self
582 }
583
584 pub fn resume(&mut self) -> &mut Self {
586 self.paused = false;
587 self
588 }
589
590 #[inline]
594 pub fn is_paused(&self) -> bool {
595 self.paused
596 }
597
598 pub fn set_repeat(&mut self, repeat: RepeatAnimation) -> &mut Self {
600 self.repeat = repeat;
601 self
602 }
603
604 pub fn repeat(&mut self) -> &mut Self {
606 self.set_repeat(RepeatAnimation::Forever)
607 }
608
609 pub fn repeat_mode(&self) -> RepeatAnimation {
611 self.repeat
612 }
613
614 pub fn completions(&self) -> u32 {
616 self.completions
617 }
618
619 pub fn is_playback_reversed(&self) -> bool {
621 self.speed < 0.0
622 }
623
624 pub fn speed(&self) -> f32 {
626 self.speed
627 }
628
629 pub fn set_speed(&mut self, speed: f32) -> &mut Self {
631 self.speed = speed;
632 self
633 }
634
635 pub fn elapsed(&self) -> f32 {
637 self.elapsed
638 }
639
640 pub fn seek_time(&self) -> f32 {
644 self.seek_time
645 }
646
647 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 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 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#[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
691impl 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#[derive(Default)]
708pub struct AnimationEvaluationState {
709 evaluators: AnimationCurveEvaluators,
722
723 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 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 pub fn play(&mut self, animation: AnimationNodeIndex) -> &mut ActiveAnimation {
824 self.active_animations.entry(animation).or_default()
825 }
826
827 pub fn stop(&mut self, animation: AnimationNodeIndex) -> &mut Self {
830 self.active_animations.remove(&animation);
831 self
832 }
833
834 pub fn stop_all(&mut self) -> &mut Self {
836 self.active_animations.clear();
837 self
838 }
839
840 pub fn playing_animations(
843 &self,
844 ) -> impl Iterator<Item = (&AnimationNodeIndex, &ActiveAnimation)> {
845 self.active_animations.iter()
846 }
847
848 pub fn playing_animations_mut(
851 &mut self,
852 ) -> impl Iterator<Item = (&AnimationNodeIndex, &mut ActiveAnimation)> {
853 self.active_animations.iter_mut()
854 }
855
856 pub fn is_playing_animation(&self, animation: AnimationNodeIndex) -> bool {
859 self.active_animations.contains_key(&animation)
860 }
861
862 pub fn all_finished(&self) -> bool {
864 self.active_animations
865 .values()
866 .all(ActiveAnimation::is_finished)
867 }
868
869 #[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 #[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 #[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 #[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 #[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 #[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 pub fn animation(&self, animation: AnimationNodeIndex) -> Option<&ActiveAnimation> {
933 self.active_animations.get(&animation)
934 }
935
936 pub fn animation_mut(&mut self, animation: AnimationNodeIndex) -> Option<&mut ActiveAnimation> {
941 self.active_animations.get_mut(&animation)
942 }
943}
944
945fn 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 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
987pub 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 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 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
1026pub type AnimationEntityMut<'w> =
1028 EntityMutExcept<'w, (AnimationTarget, AnimationPlayer, AnimationGraphHandle)>;
1029
1030pub 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 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 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 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 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 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 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 let Some(active_animation) = animation_player
1138 .active_animations
1139 .get(&animation_graph_node_index)
1140 else {
1141 continue;
1142 };
1143
1144 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 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 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#[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 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 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 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 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 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 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 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 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#[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 if is_finished && !active_animation.just_completed {
1405 return None;
1406 }
1407
1408 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 TriggeredEventsDir::Forward => {
1423 let start = events.partition_point(|event| event.time < last_time);
1424 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 TriggeredEventsDir::Reverse => {
1434 let end = events.partition_point(|event| event.time <= last_time);
1435 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 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 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 Forward,
1495 Reverse,
1497 ForwardLooping,
1499 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); 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); 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); assert_triggered_events_with(&active_animation, &clip, [0.0]);
1603 active_animation.update(0.1, clip.duration); assert_triggered_events_with(&active_animation, &clip, [0.2]);
1605 active_animation.update(0.1, clip.duration); assert_triggered_events_with(&active_animation, &clip, []);
1607 active_animation.update(0.1, clip.duration); 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); assert_triggered_events_with(&active_animation, &clip, [0.2]);
1615 active_animation.update(0.1, clip.duration); assert_triggered_events_with(&active_animation, &clip, []);
1617 active_animation.update(0.1, clip.duration); assert_triggered_events_with(&active_animation, &clip, [0.0]);
1619 active_animation.update(0.1, clip.duration); 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); assert_triggered_events_with(&active_animation, &clip, [0.0]);
1638 active_animation.update(0.1, clip.duration); assert_triggered_events_with(&active_animation, &clip, []);
1640 active_animation.update(0.1, clip.duration); assert_triggered_events_with(&active_animation, &clip, [0.2, 0.3]);
1642 active_animation.update(0.1, clip.duration); assert_triggered_events_with(&active_animation, &clip, [0.0]);
1644 active_animation.update(0.1, clip.duration); assert_triggered_events_with(&active_animation, &clip, []);
1646
1647 active_animation.speed = -1.0;
1648 active_animation.update(0.1, clip.duration); assert_triggered_events_with(&active_animation, &clip, [0.2]);
1650 active_animation.update(0.1, clip.duration); assert_triggered_events_with(&active_animation, &clip, []);
1652 active_animation.update(0.1, clip.duration); assert_triggered_events_with(&active_animation, &clip, [0.0, 0.3]);
1654 active_animation.update(0.1, clip.duration); assert_triggered_events_with(&active_animation, &clip, [0.2]);
1656 active_animation.update(0.1, clip.duration); assert_triggered_events_with(&active_animation, &clip, []);
1658
1659 active_animation.replay();
1660 active_animation.update(clip.duration, clip.duration); 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); 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}