goud_engine/ecs/components/skeleton2d/playback.rs
1//! Skeletal animation playback controller.
2//!
3//! [`SkeletalAnimator`] drives a single [`SkeletalAnimation`] at runtime,
4//! tracking elapsed time, play/pause state, and playback speed.
5
6use super::animation::SkeletalAnimation;
7use crate::ecs::Component;
8
9/// Controls playback of a [`SkeletalAnimation`] on an entity.
10///
11/// Attach alongside a [`Skeleton2D`](super::Skeleton2D) component.
12/// The [`update_skeletal_animations`](crate::ecs::systems::skeletal_animation)
13/// system advances the timer and samples keyframes each frame.
14#[derive(Debug, Clone)]
15pub struct SkeletalAnimator {
16 /// The animation clip being played.
17 pub animation: SkeletalAnimation,
18 /// Current playback position in seconds.
19 pub current_time: f32,
20 /// Whether the animator is actively advancing time.
21 pub playing: bool,
22 /// Playback speed multiplier (1.0 = normal).
23 pub speed: f32,
24}
25
26impl Component for SkeletalAnimator {}
27
28impl SkeletalAnimator {
29 /// Creates a new animator for the given animation, starting paused at t=0.
30 pub fn new(animation: SkeletalAnimation) -> Self {
31 Self {
32 animation,
33 current_time: 0.0,
34 playing: false,
35 speed: 1.0,
36 }
37 }
38
39 /// Starts or resumes playback.
40 pub fn play(&mut self) {
41 self.playing = true;
42 }
43
44 /// Pauses playback without resetting the time.
45 pub fn pause(&mut self) {
46 self.playing = false;
47 }
48
49 /// Resets playback to t=0 without changing play/pause state.
50 pub fn reset(&mut self) {
51 self.current_time = 0.0;
52 }
53
54 /// Returns `true` if a non-looping animation has reached its end.
55 pub fn is_finished(&self) -> bool {
56 !self.animation.looping && self.current_time >= self.animation.duration
57 }
58}