Skip to main content

game_toolkit_platformer/sim/
spot.rs

1//! [`Spot`]: where to put the character, by its hitbox's top-left or by its feet.
2//!
3//! Every placement takes one ([`World::new`](super::World::new), the `Platformer`'s spawn,
4//! respawn, teleport and checkpoint), so feet and top-left can't be mixed up. Tiles are not
5//! a spot: a [`Level`](super::Level) turns its spawn tile into one with
6//! [`Level::start`](super::Level::start).
7//!
8//! A spot is in the terrain's space: units, or your pixels with a `Builder::scale`.
9//!
10//! ```
11//! use game_toolkit_platformer::sim::Spot;
12//!
13//! // A 6x12 body standing on the ground at y = 100, centered on x = 50.
14//! assert_eq!(Spot::Feet(50, 100).top_left((6, 12)), (47, 88));
15//! assert_eq!(Spot::TopLeft(47, 88).top_left((6, 12)), (47, 88));
16//! ```
17
18/// A place for the character's body.
19#[derive(Clone, Copy, Debug, PartialEq, Eq)]
20pub enum Spot {
21    /// The hitbox's top-left corner at `x, y`.
22    TopLeft(i32, i32),
23    /// Standing on the ground at height `floor_y` (the ground's top edge), centered on `x`:
24    /// `Feet(x, floor_y)`. The way to put it on a terrain of your own.
25    Feet(i32, i32),
26}
27
28impl Spot {
29    /// The hitbox's top-left for a body of `(w, h)` at this spot.
30    pub fn top_left(self, (w, h): (i32, i32)) -> (i32, i32) {
31        match self {
32            Spot::TopLeft(x, y) => (x, y),
33            Spot::Feet(x, floor_y) => (x - (w + 1) / 2, floor_y - h),
34        }
35    }
36
37    /// This spot given in `k` pixels per unit, in units (rounding down).
38    pub fn in_units(self, k: i32) -> Spot {
39        let d = |v: i32| v.div_euclid(k);
40        match self {
41            Spot::TopLeft(x, y) => Spot::TopLeft(d(x), d(y)),
42            Spot::Feet(x, y) => Spot::Feet(d(x), d(y)),
43        }
44    }
45
46    /// This spot given in units, in `k` pixels per unit.
47    pub fn in_pixels(self, k: i32) -> Spot {
48        match self {
49            Spot::TopLeft(x, y) => Spot::TopLeft(x * k, y * k),
50            Spot::Feet(x, y) => Spot::Feet(x * k, y * k),
51        }
52    }
53}