//! Animated sprite module use std::{collections::HashMap, time::Duration}; use bevy::prelude::*; use bevy_ecs::system::EntityEntryCommands; /// Data for [AnimatedSprite] #[derive(Clone, PartialEq, Debug, Default, Reflect)] #[reflect(Clone, PartialEq, Debug, Default)] pub struct AnimationData { /// Handle to sprite image pub image: Handle, /// Sprite frames pub frames: Handle, /// [AnimatedSprite] duration multiplier, usually 1. pub duration_multiplier: f32, } impl AnimationData { /// Construct new [AnimationData] from given [Handle] pub fn new(image: Handle, frames: Handle, duration_multiplier: f32) -> Self { Self { image, frames, duration_multiplier } } } /// Animated sprite with states #[derive(Component, Clone, PartialEq, Debug, Reflect)] #[reflect(Component, Clone, PartialEq, Debug)] #[require(Sprite)] pub struct AnimatedSprite { data: HashMap, current: Option, timer: Timer, duration: Duration, } impl AnimatedSprite { /// Constructs new AnimatedSprite pub fn new(data: HashMap, duration: Duration) -> Self { let timer = Timer::new(duration, TimerMode::Once); Self { data, current: None, timer, duration } } /// Add new animation to sprite pub fn add(&mut self, data: AnimationData, label: String) { self.data.insert(label, data); } /// Sets internal duration pub fn set_duration(&mut self, duration: Duration) { self.duration = duration; } /// Finds animation by its label and returns it if started playing pub fn play( &mut self, label: &str, mode: TimerMode, mut sprite: EntityEntryCommands, ) -> Option<&AnimationData> { self.data.get(label).map(|data| { self.current = Some(data.clone()); self.timer = Timer::new(self.duration.mul_f32(data.duration_multiplier), mode); let sprite_image = data.image.clone(); let layout = data.frames.clone(); sprite.and_modify(move |mut sprite| { sprite.image = sprite_image; sprite.texture_atlas = Some(TextureAtlas { layout, index: 0 }); }); data }) } /// Updates animation timer pub fn tick(&mut self, dt: Duration) { self.timer.tick(dt); } /// Returns inner [Timer::fraction] pub fn fraction(&self) -> f32 { self.timer.fraction() } } /// Updates [AnimatedSprite] entities pub fn update_animated_sprites( time: Res