1#[derive(Clone, Debug)]
9pub struct AnimationDef {
10 pub name: String,
11 pub start_frame: usize,
12 pub frame_count: usize,
13 pub frame_duration: f32,
14 pub looping: bool,
15}
16
17impl AnimationDef {
18 pub fn new(
19 name: impl Into<String>,
20 start_frame: usize,
21 frame_count: usize,
22 frame_duration: f32,
23 looping: bool,
24 ) -> Self {
25 Self {
26 name: name.into(),
27 start_frame,
28 frame_count,
29 frame_duration,
30 looping,
31 }
32 }
33}
34
35pub struct AnimationState {
37 pub current_anim: String,
38 pub frame_index: usize,
39 pub timer: f32,
40 animations: Vec<AnimationDef>,
41 current_index: usize,
42}
43
44impl AnimationState {
46 pub fn new(animations: Vec<AnimationDef>, default_anim: &str) -> Self {
47 let current_index = animations
48 .iter()
49 .position(|a| a.name == default_anim)
50 .unwrap_or(0);
51 let current_anim = animations
52 .get(current_index)
53 .map(|a| a.name.clone())
54 .unwrap_or_else(|| default_anim.to_string());
55 Self {
56 current_anim,
57 frame_index: 0,
58 timer: 0.0,
59 animations,
60 current_index,
61 }
62 }
63
64 pub fn update(&mut self, dt: f32) {
66 let anim = match self.animations.get(self.current_index) {
67 Some(a) => a,
68 None => return,
69 };
70
71 self.timer += dt;
72
73 if self.timer >= anim.frame_duration {
74 self.timer -= anim.frame_duration;
75 self.frame_index += 1;
76
77 if self.frame_index >= anim.frame_count {
78 if anim.looping {
79 self.frame_index = 0;
80 } else {
81 self.frame_index = anim.frame_count.saturating_sub(1);
82 }
83 }
84 }
85 }
86
87 pub fn current(&self) -> Option<(&AnimationDef, usize)> {
89 let anim = self.animations.get(self.current_index)?;
90 Some((anim, self.frame_index))
91 }
92
93 pub fn play(&mut self, anim_name: &str) {
95 if self.current_anim != anim_name
96 && let Some(idx) = self.animations.iter().position(|a| a.name == anim_name)
97 {
98 self.current_index = idx;
99 self.current_anim = anim_name.to_string();
100 self.frame_index = 0;
101 self.timer = 0.0;
102 }
103 }
104
105 pub fn is_finished(&self) -> bool {
107 let anim = match self.animations.get(self.current_index) {
108 Some(a) => a,
109 None => return true,
110 };
111
112 !anim.looping && self.frame_index >= anim.frame_count.saturating_sub(1)
113 }
114
115 pub fn current_animation_name(&self) -> Option<&str> {
117 Some(&self.current_anim)
118 }
119
120 pub fn get_progress(&self) -> f32 {
122 if let Some(anim) = self.animations.get(self.current_index) {
123 if anim.frame_count == 0 {
124 return 0.0;
125 }
126 let total_frames = anim.frame_count;
127 let progress_per_frame = 1.0 / total_frames as f32;
128 let frame_progress = self.timer / anim.frame_duration;
129 (self.frame_index as f32 + frame_progress) * progress_per_frame
130 } else {
131 0.0
132 }
133 }
134}