use std::{
collections::HashMap,
sync::{Arc, Mutex},
time::Duration,
};
use bevy::prelude::*;
mod animations;
mod plugins;
mod types;
pub use animations::*;
pub use plugins::*;
pub use types::*;
pub mod prelude {
pub use crate::animations::{
LinearTimedAnimation, LinearTransformAnimation, SingleFrameAnimation, TimedAnimation,
TransformAnimation,
};
pub use crate::plugins::AnimationsPlugin;
pub use crate::types::{
Animation, AnimationDirection, AnimationDirectionIndexes, AnimationEvent, AnimationName,
AnimationType, Animator, FXAnimationEvent, FXBasedDirection, FlipBasedDirection,
IndexBasedDirection, NewAnimation, ResetAnimationEvent, YIndex,
};
pub use crate::{Animations, AnimationsConfig};
}
#[derive(Component, Clone)]
struct FXAnimation;
#[derive(Debug, Resource, Default)]
pub struct AnimationsConfig {
pixels_per_meter: f32,
}
#[derive(Debug, Resource, Default)]
pub struct EntitesToRemove(Vec<Entity>);
#[derive(Component, Deref, DerefMut, Clone, Debug, Default)]
pub struct AnimationTimer(pub Timer);
#[derive(Debug)]
pub struct AnimatingEntity {
pub entity: Entity,
pub in_blocking_animation: bool,
pub animations: HashMap<AnimationName, Arc<Mutex<AnimationType>>>,
pub curr_animation: Arc<Mutex<AnimationType>>,
pub curr_direction: AnimationDirection,
pub last_valid_direction: AnimationDirection,
pub curr_animation_called: bool,
pub fx_animation: bool,
}
#[derive(Default, Resource, Debug)]
pub struct Animations {
entities: HashMap<Entity, AnimatingEntity>,
animations: HashMap<AnimationName, Animation>,
fx_animations: HashMap<AnimationName, Animation>,
}
impl Animations {
pub fn insert_animation(
&mut self,
animation: NewAnimation,
entity: Option<Entity>,
) -> &mut Self {
let name = animation.animation.get_name();
let animation = Animation {
handle: animation.handle,
animation: Arc::new(Mutex::new(animation.animation)),
};
let new_animation = Arc::clone(&animation.animation);
let animation = animation;
if self.animations.get_mut(&name).is_none() {
self.animations.insert(name, animation);
}
if let Some(entity) = entity {
if let Some(animating_entity) = self.entities.get_mut(&entity) {
animating_entity
.animations
.insert(name, Arc::clone(&new_animation));
} else {
let mut map = HashMap::new();
map.insert(name, Arc::clone(&new_animation));
self.entities.insert(
entity,
AnimatingEntity {
entity,
animations: map,
curr_animation: new_animation,
curr_direction: AnimationDirection::Still,
last_valid_direction: AnimationDirection::default(),
in_blocking_animation: false,
curr_animation_called: false,
fx_animation: false,
},
);
}
}
self
}
pub fn insert_entity(&mut self, entity: Entity) -> Result<(), String> {
if self.entities.contains_key(&entity) {
return Err(format!(
"Entity {:?} already exists in `Animations`",
entity
));
}
self.entities.insert(
entity,
AnimatingEntity {
entity,
animations: HashMap::new(),
curr_animation: Arc::new(Mutex::new(AnimationType::default())),
curr_direction: AnimationDirection::Still,
last_valid_direction: AnimationDirection::default(),
in_blocking_animation: false,
curr_animation_called: false,
fx_animation: false,
},
);
Ok(())
}
pub fn add_animation_to_entity(
&mut self,
animation_name: AnimationName,
entity: Entity,
) -> Result<(), String> {
if let Some(animation) = self.animations.get_mut(&animation_name) {
let ac_animation = Arc::new(Mutex::new(animation.animation.lock().unwrap().clone()));
if let Some(entity) = self.entities.get_mut(&entity) {
if entity.animations.contains_key(&animation_name) {
return Err(format!(
"Animation {:?} already exists on entity {:?}",
animation_name, entity.entity
));
}
if entity.curr_animation.lock().unwrap().is_none() {
entity.curr_animation = Arc::clone(&ac_animation);
}
entity.animations.insert(animation_name, ac_animation);
} else {
let mut map = HashMap::new();
map.insert(animation_name, Arc::clone(&ac_animation));
self.entities.insert(
entity,
AnimatingEntity {
entity,
animations: map,
curr_animation: ac_animation,
curr_direction: AnimationDirection::Still,
last_valid_direction: AnimationDirection::default(),
in_blocking_animation: false,
curr_animation_called: false,
fx_animation: false,
},
);
}
}
Ok(())
}
pub fn get_handle(&self, animation_name: AnimationName) -> Option<Handle<TextureAtlasLayout>> {
if let Some(animation) = self.animations.get(&animation_name) {
return Some(animation.handle.clone());
}
None
}
pub fn get_fx_handle(
&self,
animation_name: AnimationName,
) -> Option<Handle<TextureAtlasLayout>> {
if let Some(animation) = self.fx_animations.get(&animation_name) {
return Some(animation.handle.clone());
}
None
}
pub fn get_entity(&mut self, entity: &Entity) -> Option<&mut AnimatingEntity> {
if let Some(animating_entity) = self.entities.get_mut(entity) {
return Some(animating_entity);
}
None
}
pub fn is_new_animation(&self, animation_name: AnimationName, entity: &Entity) -> Option<bool> {
if let Some(animating_entity) = self.entities.get(entity) {
if animating_entity.curr_animation.lock().unwrap().get_name() != animation_name {
return Some(true);
}
return Some(false);
}
None
}
pub fn has_entity(&self, entity: &Entity) -> bool {
if self.entities.contains_key(entity) {
return true;
}
false
}
pub fn insert_fx_animation(&mut self, value: NewAnimation) -> &mut Self {
let key = value.animation.get_name();
if self.fx_animations.contains_key(key) {
self
} else {
let animation = Animation {
handle: value.handle,
animation: Arc::new(Mutex::new(value.animation)),
};
self.fx_animations.insert(key, animation);
self
}
}
pub fn start_fx_animation(
&mut self,
key: Entity,
animation: AnimationName,
pos: Vec3,
) -> Result<SpriteSheetBundle, ()> {
let name = animation;
let Some(animation) = self.fx_animations.get(animation) else {
return Err(());
};
let mut animation = animation.animation.lock().unwrap().clone();
let mut atlas: TextureAtlas = self
.get_fx_handle(name)
.unwrap_or_else(|| panic!("There was a problem starting FX animation {}", name))
.into();
atlas.index = if let Some(timed_animation) = animation.timed_animation() {
timed_animation.sprite_index(&AnimationDirection::default())
} else if let Some(transform_animation) = animation.transform_animation() {
transform_animation.sprite_index(&AnimationDirection::default())
} else if let Some(linear_timed_animation) = animation.linear_timed_animation() {
linear_timed_animation.sprite_index(&AnimationDirection::default())
} else if let Some(linear_transform_animation) = animation.linear_transform_animation() {
linear_transform_animation.sprite_index(&AnimationDirection::default())
} else if let Some(single_frame_animation) = animation.single_frame_animation() {
single_frame_animation.sprite_index(&AnimationDirection::default())
} else {
panic!("Something Went Terribly Wrong Starting FX Animation");
};
self.entities.insert(
key,
AnimatingEntity {
entity: key,
in_blocking_animation: false,
animations: HashMap::new(),
curr_animation: Arc::new(Mutex::new(animation)),
curr_direction: AnimationDirection::default(),
last_valid_direction: AnimationDirection::default(),
curr_animation_called: true,
fx_animation: true,
},
);
Ok(SpriteSheetBundle {
atlas,
transform: Transform::from_translation(pos),
..Default::default()
})
}
pub fn has_animation(&self, animation_name: AnimationName) -> bool {
if self.animations.contains_key(animation_name) {
return true;
}
false
}
pub fn entity_has_animation(
&self,
animation_name: &AnimationName,
entity: Entity,
) -> Option<()> {
if let Some(animating_entity) = self.entities.get(&entity) {
if animating_entity.animations.contains_key(animation_name) {
return Some(());
}
return None;
}
None
}
pub fn in_blocking_animation(&self, entity: Entity) -> Option<bool> {
self.entities
.get(&entity)
.map(|animating_entity| animating_entity.in_blocking_animation)
}
pub fn in_animation(&self, entity: Entity) -> Option<bool> {
self.entities
.get(&entity)
.map(|animating_entity| animating_entity.curr_animation_called)
}
pub fn doing_animation(&self, entity: Entity, animation_name: AnimationName) -> Option<bool> {
self.entities.get(&entity).map(|animating_entity| {
animating_entity.curr_animation_called
&& animating_entity.curr_animation.lock().unwrap().get_name() == animation_name
})
}
pub fn is_inserted(&self, key: &Entity) -> bool {
if self.entities.contains_key(key) {
return true;
}
false
}
pub fn get_mut_map(&mut self) -> &mut HashMap<Entity, AnimatingEntity> {
&mut self.entities
}
pub fn get_map(&self) -> &HashMap<Entity, AnimatingEntity> {
&self.entities
}
}