fantasy_craft/graphics/
animations.rs1use std::sync::Arc;
2use macroquad::math::Vec2;
3
4use crate::core::plugins::Plugin;
5use crate::prelude::{GameState, Stage, System};
6use crate::scene::scene_loader::ComponentLoader;
7use crate::{graphics::sprites::Spritesheet, prelude::Context};
8use crate::physics::components::Transform;
9
10pub struct AnimationKeyFrame {
11 pub column: u32,
12 pub row: u32
13}
14
15impl AnimationKeyFrame {
16 pub fn new(column: u32, row: u32) -> Self {
17 Self { column, row }
18 }
19}
20
21pub struct Animation {
22 pub spritesheet: Arc<Spritesheet>,
23 pub frames: Vec<AnimationKeyFrame>,
24 pub current_index: f32,
25 pub speed: f32,
26 pub flip: bool
27}
28
29impl Animation {
30 pub fn new(spritesheet: Arc<Spritesheet>, frames: Vec<AnimationKeyFrame>, speed: f32, flip: bool) -> Self {
31 Self {
32 spritesheet,
33 frames,
34 current_index: 0.0,
35 speed,
36 flip
37 }
38 }
39
40 pub fn update(&mut self, dt: f32) {
41 self.current_index += self.speed * dt;
42 let num_frames = self.frames.len() as f32;
43
44 if self.current_index >= num_frames {
45 self.current_index = self.current_index.rem_euclid(num_frames);
46 }
47 }
48
49 pub fn draw(&self, x: f32, y: f32, scale: Vec2) {
50 let frame_index = self.current_index.floor() as usize;
51 let key_frame = self.frames.get(frame_index).expect("AnimationKeyFrame index out of bounds");
52 self.spritesheet.draw_sprite(key_frame.column, key_frame.row, x, y, scale, self.flip);
53 }
54}
55
56#[derive(Debug)]
57pub struct AnimationComponent(pub String);
58
59pub struct AnimationComponentLoader;
60
61impl ComponentLoader for AnimationComponentLoader {
62 fn load(&self, ctx: &mut Context, entity: hecs::Entity, data: &serde_json::Value) {
63 let animation_name: String = serde_json::from_value(data.clone())
64 .unwrap_or_default();
65
66 let component = AnimationComponent(animation_name);
67
68 ctx.world.insert_one(entity, component).expect("Failed to insert AnimationComponent");
69 }
70}
71
72pub fn update_animations(ctx: &mut Context) {
73 let dt = ctx.dt().clone();
74
75 for (_, animation_comp) in ctx.world.query::<&AnimationComponent>().iter() {
76 if let Some(animation) = ctx.asset_server.get_animation_mut(&animation_comp.0) {
77 animation.update(dt);
78 }
79 }
80}
81
82pub fn animation_render_system(ctx: &mut Context) {
83 for (_, (animation_comp, transform)) in ctx.world.query::<(&AnimationComponent, &Transform)>().iter() {
84 if let Some(animation) = ctx.asset_server.get_animation_mut(&animation_comp.0) {
85 animation.draw(transform.position.x, transform.position.y, transform.scale);
86 }
87 }
88}
89
90pub struct AnimationPlugin;
91
92impl Plugin for AnimationPlugin {
93 fn build(&self, app: &mut crate::prelude::App) {
94 app.scene_loader
95 .register("AnimationComponent", Box::new(AnimationComponentLoader));
96
97 app
98 .add_system(Stage::Update, System::new(
99 update_animations,
100 vec![GameState::Playing]
101 ))
102 .add_system(Stage::Render, System::new(
103 animation_render_system,
104 vec![GameState::Playing, GameState::Menu]
105 ));
106 }
107}