2024-08-23 11:22:09 +00:00
|
|
|
use std::{collections::HashMap, time::Duration};
|
|
|
|
|
|
|
|
use anyhow::Result;
|
|
|
|
use engine::prelude::*;
|
|
|
|
|
2024-08-25 07:11:52 +00:00
|
|
|
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
|
|
|
|
}
|
2024-08-23 11:22:09 +00:00
|
|
|
|
|
|
|
#[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<u32>,
|
|
|
|
start_time: Duration,
|
|
|
|
repeat: bool,
|
|
|
|
lock: bool,
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct AnimationInfo {
|
|
|
|
animation_map: HashMap<AnimationType, Vec<u32>>,
|
|
|
|
animation_info: Vec<AnimationData>,
|
|
|
|
|
|
|
|
animation_type: Option<AnimationType>,
|
|
|
|
animation_state: AnimationState,
|
|
|
|
lock: Option<AnimationLockInfo>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl AnimationInfo {
|
|
|
|
pub fn new(
|
|
|
|
animation_info: Vec<AnimationData>,
|
|
|
|
animation_map: HashMap<AnimationType, Vec<u32>>,
|
|
|
|
) -> Self {
|
|
|
|
Self {
|
|
|
|
animation_map,
|
|
|
|
animation_info,
|
|
|
|
|
|
|
|
animation_type: None,
|
|
|
|
animation_state: Default::default(),
|
|
|
|
|
|
|
|
lock: None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn animation_map(&self) -> &HashMap<AnimationType, Vec<u32>> {
|
|
|
|
&self.animation_map
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn animation_type(&self) -> Option<AnimationType> {
|
|
|
|
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<AnimationType>,
|
|
|
|
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"
|
|
|
|
}
|
|
|
|
}
|