banished_ui/animation.rs
1//! The interface's own clock: animated images, the containers' wheel and the edit caret.
2
3use super::*;
4
5impl Ui {
6 /// True if the current tree contains an animated image with frames and a positive frame rate.
7 pub fn has_animations(&self) -> bool {
8 self.nodes.iter().any(|node| {
9 matches!(
10 &node.kind,
11 Kind::AnimatedImage {
12 sprites,
13 frames_per_second,
14 ..
15 } if sprites.len() > 1 && *frames_per_second > 0
16 )
17 })
18 }
19
20 /// Select each animated image's frame at the supplied elapsed time in seconds.
21 /// The game's UI step: each element's own update (`AnimatedImageElement::Update`, the
22 /// containers' wheel) by `dt` seconds.
23 pub fn update(&mut self, dt: f32) {
24 self.update_containers();
25 self.update_caret(dt);
26 for node in &mut self.nodes {
27 if let Kind::AnimatedImage {
28 sprites,
29 frames_per_second,
30 frame,
31 clock,
32 ..
33 } = &mut node.kind
34 {
35 // `AnimatedImageElement::Update`: one loop lasts frames / rate seconds; past
36 // it the clock goes back by one loop, and the frame is its share of the loop.
37 if sprites.is_empty() || *frames_per_second <= 0 {
38 continue;
39 }
40 *clock += dt as f64;
41 let length = sprites.len() as f32 / *frames_per_second as f32;
42 let mut t = *clock as f32;
43 if length <= t {
44 t -= length;
45 *clock = t as f64;
46 }
47 *frame = ((t / length * sprites.len() as f32) as usize).min(sprites.len() - 1);
48 }
49 }
50 }
51
52 /// The viewer's preview: every animation at `elapsed_seconds`.
53 pub fn update_animations(&mut self, elapsed_seconds: f32) {
54 for node in &mut self.nodes {
55 if let Kind::AnimatedImage {
56 sprites,
57 frames_per_second,
58 frame,
59 ..
60 } = &mut node.kind
61 {
62 if !sprites.is_empty() && *frames_per_second > 0 {
63 *frame = ((elapsed_seconds.max(0.0) * *frames_per_second as f32).floor()
64 as usize)
65 % sprites.len();
66 }
67 }
68 }
69 }
70
71 /// Current frame, frame count, and frame rate for the first animated image in the tree.
72 pub fn animation_info(&self) -> Option<(usize, usize, i32)> {
73 self.nodes.iter().find_map(|node| match &node.kind {
74 Kind::AnimatedImage {
75 sprites,
76 frames_per_second,
77 frame,
78 ..
79 } if !sprites.is_empty() => Some((*frame, sprites.len(), *frames_per_second)),
80 _ => None,
81 })
82 }
83
84 /// Select the same frame in every animated image, wrapping each image's own frame count.
85 pub fn set_animation_frame(&mut self, frame: usize) {
86 for node in &mut self.nodes {
87 if let Kind::AnimatedImage {
88 sprites,
89 frame: current,
90 ..
91 } = &mut node.kind
92 {
93 if !sprites.is_empty() {
94 *current = frame % sprites.len();
95 }
96 }
97 }
98 }
99}