use std::{collections::HashMap, time::Duration}; use anyhow::Result; use engine::prelude::*; use crate::entityparser::AnimationData; #[derive(PartialEq, Eq, Hash, Clone, Copy, Debug, Serialize, Deserialize)] pub enum AnimationType { Move, Idle, Cast, Attack, // Add more as you need } #[derive(PartialEq, Clone, Serialize, Deserialize, Debug)] struct AnimationLockInfo { start: Duration, duration: Duration, } #[derive(Debug, Default, PartialEq, Eq, Clone, Serialize, Deserialize)] pub struct AnimationState { index: Option, start_time: Duration, repeat: bool, lock: bool, } pub struct AnimationInfo { animation_map: HashMap>, animation_info: Vec, animation_type: Option, animation_state: AnimationState, lock: Option, } impl AnimationInfo { pub fn new( animation_info: Vec, animation_map: HashMap>, ) -> Self { Self { animation_map, animation_info, animation_type: None, animation_state: Default::default(), lock: None, } } pub fn animation_map(&self) -> &HashMap> { &self.animation_map } pub fn animation_type(&self) -> Option { self.animation_type } pub fn is_locked(&self) -> bool { self.lock.is_some() } /// Returns true if there is no lock, otherwise the animation is locked pub fn check_lock(&mut self, now: Duration) -> bool { match &mut self.lock { Some(lock) => { if now < lock.start { panic!("Animation::check_lock: `now < start` !?"); } if (now - lock.start) < lock.duration { false } else { self.lock = None; true } } None => true, } } /// Make sure `start` is `scene_time`, otherwise you will experience strange behavior pub fn set_animation( &mut self, animation: &mut Animation, draw: &mut Draw, animation_type: Option, start: Duration, lock: bool, mut repeat: bool, ) -> Result<()> { debug_assert!(self.lock.is_none()); self.animation_type = animation_type; match animation_type { Some(animation_type) => { if let Some(animation_indices) = self.animation_map.get(&animation_type) { assert!(!animation_indices.is_empty()); let index = if animation_indices.len() > 1 { animation_indices[Random::range(0, animation_indices.len() as u32) as usize] } else { animation_indices[0] }; if lock { repeat = false; let duration = self.animation_info[index as usize].duration; self.lock = Some(AnimationLockInfo { start, duration }); } self.animation_state = AnimationState { index: Some(index), start_time: start, repeat, lock, }; unsafe { animation.set_animation(draw, Some(index), start, repeat)? }; } } None => { self.lock = None; self.animation_state = AnimationState { index: None, start_time: Duration::default(), repeat: false, lock: false, }; unsafe { animation.set_animation(draw, None, Duration::default(), false)? }; } } Ok(()) } } impl Clone for AnimationInfo { fn clone(&self) -> Self { Self { animation_map: self.animation_map.clone(), animation_info: self.animation_info.clone(), animation_type: None, animation_state: AnimationState::default(), lock: None, } } } impl EntityComponent for AnimationInfo { fn name(&self) -> &str { Self::debug_name() } } impl ComponentDebug for AnimationInfo { fn debug_name() -> &'static str { "AnimationInfo" } }