1use crate::math::Vec2;
11
12#[derive(Debug, Clone)]
18pub struct Animation {
19 pub name: String,
21 pub frame_size: Vec2,
23 pub frames: Vec<AnimationFrame>,
25 pub speed: f32,
27 pub looping: bool,
29 pub ping_pong: bool,
31 pub offset: Vec2,
33}
34
35#[derive(Debug, Clone)]
37pub struct AnimationFrame {
38 pub column: u32,
40 pub row: u32,
42 pub duration: f32,
45 pub event: Option<String>,
47}
48
49impl Animation {
50 pub fn from_row(
58 name: &str,
59 row: u32,
60 start_col: u32,
61 end_col: u32,
62 frame_duration: f32,
63 ) -> Self {
64 let frames = (start_col..=end_col)
65 .map(|col| AnimationFrame {
66 column: col,
67 row,
68 duration: frame_duration,
69 event: None,
70 })
71 .collect();
72
73 Self {
74 name: name.to_string(),
75 frame_size: Vec2::ZERO,
76 frames,
77 speed: 1.0,
78 looping: true,
79 ping_pong: false,
80 offset: Vec2::ZERO,
81 }
82 }
83
84 pub fn with_frame_size(mut self, w: f32, h: f32) -> Self {
86 self.frame_size = Vec2::new(w, h);
87 self
88 }
89
90 pub fn with_speed(mut self, speed: f32) -> Self {
92 self.speed = speed;
93 self
94 }
95
96 pub fn with_looping(mut self, looping: bool) -> Self {
98 self.looping = looping;
99 self
100 }
101
102 pub fn with_ping_pong(mut self) -> Self {
104 self.ping_pong = true;
105 self
106 }
107
108 pub fn with_offset(mut self, x: f32, y: f32) -> Self {
110 self.offset = Vec2::new(x, y);
111 self
112 }
113
114 pub fn with_frame_event(mut self, frame_index: usize, event: &str) -> Self {
116 if frame_index < self.frames.len() {
117 self.frames[frame_index].event = Some(event.to_string());
118 }
119 self
120 }
121
122 pub fn total_duration(&self) -> f32 {
124 self.frames.iter().map(|f| f.duration).sum::<f32>() / self.speed
125 }
126
127 pub fn frame_count(&self) -> usize {
129 self.frames.len()
130 }
131}
132
133#[derive(Debug, Clone, Copy, PartialEq, Eq)]
139pub enum AnimationState {
140 Playing,
142 Finished,
144 Paused,
146}
147
148#[derive(Debug)]
163pub struct AnimationPlayer {
164 current: Option<Animation>,
166 frame_index: usize,
168 frame_timer: f32,
170 state: AnimationState,
172 forward: bool,
174 pending_events: Vec<String>,
176}
177
178impl Default for AnimationPlayer {
179 fn default() -> Self {
180 Self::new()
181 }
182}
183
184impl AnimationPlayer {
185 pub fn new() -> Self {
187 Self {
188 current: None,
189 frame_index: 0,
190 frame_timer: 0.0,
191 state: AnimationState::Finished,
192 forward: true,
193 pending_events: Vec::new(),
194 }
195 }
196
197 pub fn play(&mut self, anim: &Animation) {
202 let is_same = self.current.as_ref().map(|c| c.name == anim.name).unwrap_or(false);
203 if !is_same || self.state == AnimationState::Finished {
204 self.current = Some(anim.clone());
205 self.frame_index = 0;
206 self.frame_timer = 0.0;
207 self.state = AnimationState::Playing;
208 self.forward = true;
209 self.pending_events.clear();
210 }
211 }
212
213 pub fn restart(&mut self) {
215 self.frame_index = 0;
216 self.frame_timer = 0.0;
217 self.state = AnimationState::Playing;
218 self.forward = true;
219 }
220
221 pub fn pause(&mut self) {
223 if self.state == AnimationState::Playing {
224 self.state = AnimationState::Paused;
225 }
226 }
227
228 pub fn resume(&mut self) {
230 if self.state == AnimationState::Paused {
231 self.state = AnimationState::Playing;
232 }
233 }
234
235 pub fn stop(&mut self) {
237 self.current = None;
238 self.frame_index = 0;
239 self.frame_timer = 0.0;
240 self.state = AnimationState::Finished;
241 }
242
243 pub fn current_name(&self) -> Option<&str> {
245 self.current.as_ref().map(|a| a.name.as_str())
246 }
247
248 pub fn current_frame_rect(&self) -> Option<(u32, u32, f32, f32)> {
250 let anim = self.current.as_ref()?;
251 let frame = anim.frames.get(self.frame_index)?;
252 Some((frame.column, frame.row, anim.frame_size.x, anim.frame_size.y))
253 }
254
255 pub fn frame_index(&self) -> usize {
257 self.frame_index
258 }
259
260 pub fn state(&self) -> AnimationState {
262 self.state
263 }
264
265 pub fn offset(&self) -> Vec2 {
267 self.current.as_ref().map(|a| a.offset).unwrap_or(Vec2::ZERO)
268 }
269
270 pub fn update(&mut self, dt: f32) -> &[String] {
272 self.pending_events.clear();
273
274 if self.state != AnimationState::Playing {
275 return &self.pending_events;
276 }
277
278 let anim = match &self.current {
279 Some(a) => a,
280 None => return &self.pending_events,
281 };
282
283 if anim.frames.is_empty() {
284 self.state = AnimationState::Finished;
285 return &self.pending_events;
286 }
287
288 let frame = &anim.frames[self.frame_index];
289 let effective_duration = if frame.duration > 0.0 {
290 frame.duration / anim.speed
291 } else {
292 0.1 / anim.speed
293 };
294
295 self.frame_timer += dt;
296
297 if self.frame_timer >= effective_duration {
298 self.frame_timer -= effective_duration;
299
300 if let Some(event) = &frame.event {
302 self.pending_events.push(event.clone());
303 }
304
305 if anim.ping_pong {
307 if self.forward {
308 if self.frame_index + 1 >= anim.frames.len() {
309 self.forward = false;
310 self.frame_index = self.frame_index.saturating_sub(1);
311 } else {
312 self.frame_index += 1;
313 }
314 } else {
315 if self.frame_index == 0 {
316 if anim.looping {
317 self.forward = true;
318 self.frame_index = 1;
319 } else {
320 self.state = AnimationState::Finished;
321 }
322 } else {
323 self.frame_index -= 1;
324 }
325 }
326 } else {
327 if self.frame_index + 1 >= anim.frames.len() {
328 if anim.looping {
329 self.frame_index = 0;
330 } else {
331 self.state = AnimationState::Finished;
332 }
333 } else {
334 self.frame_index += 1;
335 }
336 }
337 }
338
339 &self.pending_events
340 }
341}