use std::fmt::Debug;
use anyhow::anyhow;
use super::SpriteDesc;
use crate::{animation::traits::AnimationAssets, prelude::*};
const DEFAULT_KEY: &str = "default";
#[derive(Clone)]
pub struct Animator<TextureKey> {
pub request_key: Option<String>,
pub sprite_desc: SpriteDesc<TextureKey>,
pub current: u16,
pub repeat: bool,
pub tick: f32,
}
impl<TextureKey: Default> Default for Animator<TextureKey> {
fn default() -> Self {
Self {
request_key: None,
sprite_desc: SpriteDesc {
texture_key: Default::default(),
start: 0,
end: 0,
frame_secs: 0.1,
tile_size: UVec2::splat(32),
scale: 1.0,
angle: 0.0,
},
current: 0,
repeat: false,
tick: 0.0,
}
}
}
impl<TextureKey: Clone + Debug> Animator<TextureKey> {
pub fn is_finished(&self) -> bool {
self.current == self.sprite_desc.end && !self.repeat
}
pub fn request_state(&mut self, key: String) {
self.request_key = Some(key);
}
pub fn update(
assets: &impl AnimationAssets<TextureKey>,
tick: f32,
animators: &mut Component<Self>,
) {
for e in animators.iter_mut() {
let anim = &mut e.value;
if let Some(request_key) = anim.request_key.take() {
let Some(desc) = assets
.get_sprite_desc(&request_key)
.or_else(|| assets.get_sprite_desc(DEFAULT_KEY))
else {
continue;
};
anim.current = desc.start;
anim.sprite_desc = desc.clone();
anim.tick = 0.0;
}
anim.tick -= tick;
if anim.tick < 0.0 {
if anim.is_finished() {
continue;
}
if anim.current < anim.sprite_desc.end {
anim.current += 1;
} else if anim.repeat {
anim.current = anim.sprite_desc.start;
}
anim.tick = anim.sprite_desc.frame_secs;
}
}
}
pub fn draw(
&self,
g: &mut Engine,
assets: &impl AnimationAssets<TextureKey>,
tf: &Transform,
) -> Result<()> {
let sprite = assets
.get_texture(&self.sprite_desc.texture_key)
.cloned()
.ok_or_else(|| anyhow!("missing sprite {:?}", self.sprite_desc.texture_key))?;
let tile_size = self.sprite_desc.tile_size.as_vec2();
let sprite = sprite.with_tile(self.current, tile_size);
g.draw(&sprite, *tf);
Ok(())
}
pub fn current_frame(&self) -> u16 {
self.current
}
pub fn set_repeat(&mut self, repeat: bool) {
self.repeat = repeat;
}
}