bones_framework/
animation.rs1use crate::prelude::*;
4
5pub fn animation_plugin(core: &mut SessionBuilder) {
7 core.stages
8 .add_system_to_stage(CoreStage::Last, update_animation_banks)
9 .add_system_to_stage(CoreStage::Last, animate_sprites);
10}
11
12#[derive(Clone, HasSchema, Debug)]
14#[repr(C)]
15pub struct AnimatedSprite {
16 pub index: u32,
18 pub frames: SVec<u32>,
23 pub fps: f32,
25 pub timer: f32,
27 pub repeat: bool,
29}
30
31#[derive(Clone, HasSchema, Debug, Default)]
37pub struct AnimationBankSprite {
38 pub current: Ustr,
40 pub animations: SMap<Ustr, AnimatedSprite>,
43 pub last_animation: Ustr,
45}
46
47impl AnimationBankSprite {
48 pub fn set_current(&mut self, animation_name: impl Into<Ustr>) {
50 let animation_name = animation_name.into();
51 if self.animations.contains_key(&animation_name) {
52 self.current = animation_name;
53 }
54 }
55
56 pub fn insert_animation(&mut self, name: impl Into<Ustr>, animation: AnimatedSprite) {
58 let name = name.into();
59 self.animations.insert(name, animation);
60 }
61
62 pub fn remove_animation(&mut self, name: &Ustr) -> Option<AnimatedSprite> {
64 self.animations.remove(name)
65 }
66
67 pub fn get_animation(&self, name: &Ustr) -> Option<&AnimatedSprite> {
69 self.animations.get(name)
70 }
71
72 pub fn get_animation_mut(&mut self, name: &Ustr) -> Option<&mut AnimatedSprite> {
74 self.animations.get_mut(name)
75 }
76
77 pub fn get_current_animation(&self) -> Option<&AnimatedSprite> {
79 self.animations.get(&self.current)
80 }
81
82 pub fn get_current_animation_mut(&mut self) -> Option<&mut AnimatedSprite> {
84 self.animations.get_mut(&self.current)
85 }
86}
87
88impl Default for AnimatedSprite {
89 fn default() -> Self {
90 Self {
91 index: 0,
92 frames: default(),
93 fps: 0.0,
94 timer: 0.0,
95 repeat: true,
96 }
97 }
98}
99
100pub fn animate_sprites(
102 time: Res<Time>,
103 entities: Res<Entities>,
104 mut atlas_sprites: CompMut<AtlasSprite>,
105 mut animated_sprites: CompMut<AnimatedSprite>,
106) {
107 for (_ent, (atlas_sprite, animated_sprite)) in
108 entities.iter_with((&mut atlas_sprites, &mut animated_sprites))
109 {
110 if animated_sprite.frames.is_empty() {
111 continue;
112 }
113
114 animated_sprite.timer += time.delta_seconds();
115
116 if (animated_sprite.index != animated_sprite.frames.len() as u32 - 1
118 || animated_sprite.repeat)
119 && animated_sprite.timer > 1.0 / animated_sprite.fps.max(f32::MIN_POSITIVE)
120 {
121 animated_sprite.timer = 0.0;
123
124 animated_sprite.index =
126 (animated_sprite.index + 1) % animated_sprite.frames.len() as u32;
127 }
128
129 atlas_sprite.index = animated_sprite.frames[animated_sprite.index as usize];
131 }
132}
133
134pub fn update_animation_banks(
136 entities: Res<Entities>,
137 mut animation_bank_sprites: CompMut<AnimationBankSprite>,
138 mut animated_sprites: CompMut<AnimatedSprite>,
139) {
140 for (ent, animation_bank) in entities.iter_with(&mut animation_bank_sprites) {
141 if animation_bank.current != animation_bank.last_animation {
143 animation_bank.last_animation = animation_bank.current;
145
146 let animated_sprite = animation_bank
148 .get_current_animation()
149 .cloned()
150 .unwrap_or_else(|| {
151 panic!("Animation `{}` does not exist.", animation_bank.current)
152 });
153
154 animated_sprites.insert(ent, animated_sprite);
156 }
157 }
158}