diff options
| author | Freya Murphy <freya@freyacat.org> | 2025-10-23 13:08:40 -0400 |
|---|---|---|
| committer | Freya Murphy <freya@freyacat.org> | 2025-10-23 13:10:19 -0400 |
| commit | 0c3e9c8dc49ff11d7612bd7e0bc25030ae566ab1 (patch) | |
| tree | e286028ebb74c5ffd08433dd8ff25d6149b68afc /dungeon/src/pos.rs | |
| parent | Started implementing wfc crate into map (diff) | |
| download | DungeonCrawl-0c3e9c8dc49ff11d7612bd7e0bc25030ae566ab1.tar.gz DungeonCrawl-0c3e9c8dc49ff11d7612bd7e0bc25030ae566ab1.tar.bz2 DungeonCrawl-0c3e9c8dc49ff11d7612bd7e0bc25030ae566ab1.zip | |
dungeon: add FPos for decimial positions
Diffstat (limited to 'dungeon/src/pos.rs')
| -rw-r--r-- | dungeon/src/pos.rs | 142 |
1 files changed, 142 insertions, 0 deletions
diff --git a/dungeon/src/pos.rs b/dungeon/src/pos.rs index 4947ce2..dc1bd2d 100644 --- a/dungeon/src/pos.rs +++ b/dungeon/src/pos.rs @@ -2,6 +2,8 @@ //! entity or objects position and facing direction inside the //! dungeon grid. +use std::ops::{AddAssign, SubAssign}; + use crate::{MAP_SIZE_USIZE, map::MAP_SIZE}; macro_rules! downcast { @@ -253,3 +255,143 @@ impl Default for Pos { const_pos!(0, 0) } } +impl TryFrom<usize> for Pos { + type Error = (); + + fn try_from(value: usize) -> Result<Self, Self::Error> { + Self::from_idx(value).ok_or(()) + } +} + +/// The `FPos` type represents a floating 2D (temp) position. +/// +/// This position is not gurenteed to be inside the dungeon grid. FPos exists to +/// tween between two different `Pos`. All bounds checks should be done in `Pos` before updating +/// the underlying Floating Position. +#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)] +pub struct FPos(f32, f32); +impl FPos { + /// Creates a new position from a given floating x and y position. + /// + /// Returns `None` if the position goes out of the map. + /// + /// # Examples + /// + /// ``` + /// use dungeon::FPos; + /// + /// let fpos = FPos::new(5.4,6.7); + /// ``` + #[must_use] + pub const fn new(x: f32, y: f32) -> Self { + Self(x, y) + } + + /// Creates a new `FPos` using the checked/fixed `Pos`. + /// + /// # Examples + /// + /// ``` + /// use dungeon::{Pos, FPos}; + /// + /// let pos = Pos::new(1, 1).unwrap(); + /// let fpos = FPos::from_pos(pos); + /// ``` + #[must_use] + pub const fn from_pos(pos: Pos) -> Self { + let (x, y) = pos.xy(); + Self(x as f32, y as f32) + } + + /// Returns the x and y positions of `FPos`. + /// + /// # Examples + /// + /// ``` + /// use dungeon::FPos; + /// + /// let fpos = FPos::new(5.0,7.2); + /// let (x,y) = fpos.xy(); + /// assert_eq!(x, 5.0); + /// assert_eq!(y, 7.2); + /// ``` + #[must_use] + pub const fn xy(self) -> (f32, f32) { + (self.0, self.1) + } + + /// Steps `FPos` a given floating amount in the `Direction` `dir`. + /// + /// Returns `None` if the floating position wraps. + /// + /// # Examples + /// + /// ``` + /// use dungeon::{Direction, FPos}; + /// + /// let fpos = FPos::new(0.0, 1.0); + /// let new_fpos = fpos.step(Direction::North, 0.3); + /// assert!(new_fpos.is_some()); + /// ``` + /// + /// ``` + /// use dungeon::{Direction, FPos}; + /// + /// let fpos = FPos::new(0.0, 0.0); + /// let new_fpos = fpos.step(Direction::North, 5.0); + /// assert!(new_fpos.is_none()); + /// ``` + #[must_use] + pub fn step(self, dir: Direction, amt: f32) -> Option<Self> { + use Direction as D; + let (mut x, mut y) = self.xy(); + match dir { + D::North if y >= amt => y.sub_assign(amt), + D::South => y.add_assign(amt), + D::East => x.add_assign(amt), + D::West if x >= amt => x.sub_assign(amt), + _ => return None, + }; + Some(Self(x, y)) + } + + /// Computes the absolute difference between to positions + /// + /// # Examples + /// + /// ``` + /// use dungeon::FPos; + /// + /// let fpos1 = FPos::new(1.0,0.0); + /// let fpos2 = FPos::new(0.0,1.0); + /// let diff = fpos1.abs_diff(fpos2); + /// assert_eq!(diff.xy(), (1.0, 1.0)); + /// ``` + /// + #[must_use] + pub fn abs_diff(self, other: Self) -> Self { + let x = (self.0 - other.0).abs(); + let y = (self.1 - other.1).abs(); + Self(x, y) + } +} +impl Default for FPos { + /// Returns a default postion at the origin (0,0) + /// + /// ``` + /// use dungeon::FPos; + /// + /// let fpos = FPos::default(); + /// + /// assert_eq!(fpos.xy(), (0.0, 0.0)); + /// ``` + /// + fn default() -> Self { + Self::new(0.0, 0.0) + } +} +impl From<Pos> for FPos { + fn from(value: Pos) -> Self { + Self::from_pos(value) + } +} |