flatland_presentation/
directional.rs1pub const PLAYER_DIRECTIONAL_BASE_MODES: &[&str] = &["idle", "walk", "run"];
5
6pub fn cardinal_facing_label(yaw: f32) -> &'static str {
8 let deg = yaw.to_degrees().rem_euclid(360.0);
9 if (45.0..135.0).contains(°) {
10 "east"
11 } else if (135.0..225.0).contains(°) {
12 "south"
13 } else if (225.0..315.0).contains(°) {
14 "west"
15 } else {
16 "north"
17 }
18}
19
20pub fn base_sprite_mode(mode: &str) -> &str {
22 for suffix in ["_north", "_east", "_south", "_west"] {
23 if let Some(base) = mode.strip_suffix(suffix) {
24 return base;
25 }
26 }
27 mode
28}
29
30pub fn sheet_has_mode(sheet_modes: &[String], mode: &str) -> bool {
32 if sheet_modes.iter().any(|m| m == mode) {
33 return true;
34 }
35 let prefix = format!("{mode}_");
36 sheet_modes.iter().any(|m| m.starts_with(&prefix))
37}
38
39pub fn expand_directional_draw_mode(
41 sheet_modes: &[String],
42 base_mode: &str,
43 facing_yaw: f32,
44) -> String {
45 let base = base_sprite_mode(base_mode);
46 if !PLAYER_DIRECTIONAL_BASE_MODES.contains(&base) {
47 return base.to_string();
48 }
49 let directional = format!("{}_{}", base, cardinal_facing_label(facing_yaw));
50 if sheet_has_mode(sheet_modes, &directional) {
51 directional
52 } else {
53 base.to_string()
54 }
55}
56
57#[cfg(test)]
58mod tests {
59 use super::*;
60
61 fn modes(ids: &[&str]) -> Vec<String> {
62 ids.iter().map(|s| s.to_string()).collect()
63 }
64
65 #[test]
66 fn cardinal_facing_label_bins() {
67 assert_eq!(cardinal_facing_label(0.0), "north");
68 assert_eq!(cardinal_facing_label(std::f32::consts::FRAC_PI_2), "east");
69 assert_eq!(cardinal_facing_label(std::f32::consts::PI), "south");
70 }
71
72 #[test]
73 fn base_sprite_mode_strips_suffix() {
74 assert_eq!(base_sprite_mode("walk_north"), "walk");
75 assert_eq!(base_sprite_mode("idle"), "idle");
76 }
77
78 #[test]
79 fn expand_directional_when_sheet_has_variant() {
80 let sheet = modes(&["idle_north", "walk_north", "walk_east", "combat"]);
81 assert_eq!(
82 expand_directional_draw_mode(&sheet, "walk", 0.0),
83 "walk_north"
84 );
85 assert_eq!(
86 expand_directional_draw_mode(&sheet, "walk", std::f32::consts::FRAC_PI_2),
87 "walk_east"
88 );
89 assert_eq!(expand_directional_draw_mode(&sheet, "combat", 0.0), "combat");
90 }
91
92 #[test]
93 fn expand_falls_back_to_base_without_directional() {
94 let sheet = modes(&["walk", "idle"]);
95 assert_eq!(expand_directional_draw_mode(&sheet, "walk", 0.0), "walk");
96 }
97}