feat: More AnimatedSprite methods

This commit is contained in:
Alexey 2026-04-21 13:09:03 +03:00
commit be36504a00

View file

@ -5,6 +5,8 @@ use std::{collections::HashMap, time::Duration};
use bevy::prelude::*; use bevy::prelude::*;
use bevy_ecs::system::EntityEntryCommands; use bevy_ecs::system::EntityEntryCommands;
type SpriteCommands<'a> = EntityEntryCommands<'a, Sprite>;
/// Data for [AnimatedSprite] /// Data for [AnimatedSprite]
#[derive(Clone, PartialEq, Debug, Default, Reflect)] #[derive(Clone, PartialEq, Debug, Default, Reflect)]
#[reflect(Clone, PartialEq, Debug, Default)] #[reflect(Clone, PartialEq, Debug, Default)]
@ -19,6 +21,7 @@ pub struct AnimationData {
impl AnimationData { impl AnimationData {
/// Construct new [AnimationData] from given [Handle<TextureAtlasLayout>] /// Construct new [AnimationData] from given [Handle<TextureAtlasLayout>]
#[inline(always)]
pub fn new(image: Handle<Image>, frames: Handle<TextureAtlasLayout>, duration_multiplier: f32) -> Self { pub fn new(image: Handle<Image>, frames: Handle<TextureAtlasLayout>, duration_multiplier: f32) -> Self {
Self { image, frames, duration_multiplier } Self { image, frames, duration_multiplier }
} }
@ -33,36 +36,41 @@ pub struct AnimatedSprite {
current: Option<AnimationData>, current: Option<AnimationData>,
timer: Timer, timer: Timer,
duration: Duration, duration: Duration,
backwards: bool,
} }
impl AnimatedSprite { impl AnimatedSprite {
/// Constructs new AnimatedSprite /// Constructs new AnimatedSprite
#[inline(always)]
pub fn new(data: HashMap<String, AnimationData>, duration: Duration) -> Self { pub fn new(data: HashMap<String, AnimationData>, duration: Duration) -> Self {
let timer = Timer::new(duration, TimerMode::Once); let timer = Timer::new(duration, TimerMode::Once);
Self { data, current: None, timer, duration } Self { data, current: None, timer, duration, backwards: false }
} }
/// Add new animation to sprite /// Add new animation to sprite
#[inline(always)]
pub fn add(&mut self, data: AnimationData, label: String) { pub fn add(&mut self, data: AnimationData, label: String) {
self.data.insert(label, data); self.data.insert(label, data);
} }
/// Sets internal duration /// Sets internal duration
#[inline(always)]
pub fn set_duration(&mut self, duration: Duration) { pub fn set_duration(&mut self, duration: Duration) {
self.duration = duration; self.duration = duration;
} }
/// Finds animation by its label and returns it if started playing fn play_inner(
pub fn play(
&mut self, &mut self,
label: &str, label: &str,
mode: TimerMode, mode: TimerMode,
mut sprite: EntityEntryCommands<Sprite>, mut sprite: SpriteCommands,
backwards: bool,
) -> Option<&AnimationData> { ) -> Option<&AnimationData> {
self.data.get(label).map(|data| { self.data.get(label).map(|data| {
self.current = Some(data.clone()); self.current = Some(data.clone());
self.timer = Timer::new(self.duration.mul_f32(data.duration_multiplier), mode); self.timer = Timer::new(self.duration.mul_f32(data.duration_multiplier), mode);
self.backwards = backwards;
let sprite_image = data.image.clone(); let sprite_image = data.image.clone();
let layout = data.frames.clone(); let layout = data.frames.clone();
@ -75,15 +83,55 @@ impl AnimatedSprite {
data data
}) })
} }
/// Finds animation by its label, plays it and returns it if started playing
#[inline(always)]
pub fn play(
&mut self,
label: &str,
mode: TimerMode,
sprite: SpriteCommands,
) -> Option<&AnimationData> {
self.play_inner(label, mode, sprite, false)
}
/// Same as [play](AnimatedSprite::play), but animation plays from the end to the beginning
#[inline(always)]
pub fn play_backwards(
&mut self,
label: &str,
mode: TimerMode,
sprite: SpriteCommands,
) -> Option<&AnimationData> {
self.play_inner(label, mode, sprite, true)
}
/// Stops the animation
#[inline(always)]
pub fn stop(&mut self) {
self.current = None;
self.timer.reset();
}
/// Updates animation timer /// Updates animation timer
#[inline(always)]
pub fn tick(&mut self, dt: Duration) { pub fn tick(&mut self, dt: Duration) {
self.timer.tick(dt); self.timer.tick(dt);
} }
/// Returns inner [Timer::fraction] /// Returns inner [Timer::fraction] or [Timer::fraction_remaining] if playing backwards
#[inline(always)]
pub fn fraction(&self) -> f32 { pub fn fraction(&self) -> f32 {
self.timer.fraction() match self.backwards {
true => self.timer.fraction_remaining(),
false => self.timer.fraction(),
}
}
/// Returns [Timer::mode]
#[inline(always)]
pub fn mode(&self) -> TimerMode {
self.timer.mode()
} }
} }
@ -107,7 +155,7 @@ pub fn update_animated_sprites(
let max_frames = atlas.len() as f32; let max_frames = atlas.len() as f32;
let current_frame = (max_frames * animation.fraction()) as usize; let current_frame = (max_frames * animation.fraction()).min(max_frames - 1.) as usize;
if let Some(atlas) = &mut sprite.texture_atlas { if let Some(atlas) = &mut sprite.texture_atlas {
atlas.index = current_frame; atlas.index = current_frame;