Skip to main content

game_toolkit_platformer/
debug_draw.rs

1//! A debug look with game-toolkit's painter: a [`Level`] as blocks, the character as a
2//! box colored by its animation state with the state's name above it. Enough to play and
3//! tune before there is any art.
4
5use game_toolkit::prelude::*;
6
7use crate::Platformer;
8use crate::sim::{Level, Tile};
9
10impl Level {
11    /// Draw the tiles and the dash refills that are there with `p`, the level's
12    /// top-left at `origin` (window pixels), `scale` window pixels per unit.
13    pub fn draw_debug(&self, p: &mut Painter<'_>, origin: [f32; 2], scale: f32) {
14        let at = |x: f32, y: f32| [origin[0] + x * scale, origin[1] + y * scale];
15        let t = self.tile_size() as f32;
16        for ty in 0..self.height() {
17            for tx in 0..self.width() {
18                let (x, y) = (tx as f32 * t, ty as f32 * t);
19                match self.tile(tx, ty) {
20                    Tile::Empty => {}
21                    Tile::Solid => {
22                        p.rect(at(x, y), [t * scale, t * scale], Color::rgb8(74, 64, 100));
23                    }
24                    Tile::Platform => {
25                        p.rect(
26                            at(x, y),
27                            [t * scale, 2.0 * scale],
28                            Color::rgb8(156, 112, 66),
29                        );
30                    }
31                    Tile::Custom(k) => {
32                        // A small square, its shade by number, so kinds tell apart.
33                        let shade = 120u8.wrapping_add(k.wrapping_mul(53));
34                        p.rect(
35                            at(x + 2.0, y + 2.0),
36                            [(t - 4.0) * scale, (t - 4.0) * scale],
37                            Color::rgb8(200, shade, 120),
38                        );
39                    }
40                }
41            }
42        }
43        for c in self.refills().iter().filter(|c| c.ready()) {
44            let a = c.area;
45            let (q, side) = (a.w as f32 / 4.0, a.w as f32 / 2.0);
46            p.rect(
47                at(a.x as f32 + q, a.y as f32 + q),
48                [side * scale, side * scale],
49                Color::rgb8(253, 196, 67),
50            );
51        }
52    }
53}
54
55impl Platformer {
56    /// Draw the character as a box colored by its animation state, an eye on the side it
57    /// faces and the state's name above, with `p`: the world's origin at `origin` (window
58    /// pixels), `scale` window pixels per unit.
59    pub fn draw_debug(&self, p: &mut Painter<'_>, origin: [f32; 2], scale: f32) {
60        let at = |x: f32, y: f32| [origin[0] + x * scale, origin[1] + y * scale];
61        let (x, y) = self.position();
62        let r = self.hitbox();
63        p.rect(
64            at(x, y),
65            [r.w as f32 * scale, r.h as f32 * scale],
66            state_color(self.state()),
67        );
68        let eye_x = if self.facing() > 0 {
69            x + r.w as f32 - 2.0
70        } else {
71            x + 1.0
72        };
73        p.rect(
74            at(eye_x, y + 2.0),
75            [scale, scale],
76            Color::rgb8(255, 255, 255),
77        );
78        p.text(
79            at(x - 4.0, y - 6.0),
80            self.state(),
81            3.5 * scale,
82            Color::rgb8(194, 203, 232),
83        );
84    }
85}
86
87/// A steady, distinct color per state name, so state changes are visible at a glance.
88fn state_color(name: &str) -> Color {
89    let h = name
90        .bytes()
91        .fold(2166136261u32, |h, b| (h ^ b as u32).wrapping_mul(16777619));
92    let (r, g, b) = (
93        (h & 0xff) as u8,
94        ((h >> 8) & 0xff) as u8,
95        ((h >> 16) & 0xff) as u8,
96    );
97    // Keep it bright enough on a dark background.
98    Color::rgb8(r / 2 + 110, g / 2 + 110, b / 2 + 110)
99}