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 | |
| 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')
| -rw-r--r-- | dungeon/src/entity.rs | 10 | ||||
| -rw-r--r-- | dungeon/src/lib.rs | 8 | ||||
| -rw-r--r-- | dungeon/src/pos.rs | 142 |
3 files changed, 156 insertions, 4 deletions
diff --git a/dungeon/src/entity.rs b/dungeon/src/entity.rs index f997b99..4ea6725 100644 --- a/dungeon/src/entity.rs +++ b/dungeon/src/entity.rs @@ -1,6 +1,6 @@ //! The `entity` module contains structures of all entities including players and enimies. -use crate::{Direction, Pos, const_pos}; +use crate::{Direction, FPos, Pos, const_pos}; /// The `Item` type represents any item an entity may be using #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] @@ -22,10 +22,12 @@ pub enum EntityKind { /// The `Entity` kind represents the main player, or any other /// ai autonomous character that can move freely across the /// dungeon. -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Copy, Debug, PartialEq)] pub struct Entity { /// The fixed grid position of the entity pub pos: Pos, + /// The floating (real) current position of the entity + pub fpos: FPos, /// Which direction this entity is facing pub dir: Direction, /// Which kind this entity is (along with entity kind specific data) @@ -54,8 +56,10 @@ impl Entity { kind: EntityKind, health: Option<u32>, ) -> Self { + let fpos = FPos::from_pos(pos); Self { pos, + fpos, dir, kind, health, @@ -82,7 +86,7 @@ impl Entity { } /// The `Player` type represents the main player entity -#[derive(Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Debug, PartialEq)] pub struct Player { pub entity: Entity, pub inventory: Vec<Item>, diff --git a/dungeon/src/lib.rs b/dungeon/src/lib.rs index 75400e9..0e1a501 100644 --- a/dungeon/src/lib.rs +++ b/dungeon/src/lib.rs @@ -12,7 +12,7 @@ pub use pos::*; /// The `Dungeon` type represents the game state of the /// dungeon crawler. -#[derive(Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Debug, PartialEq)] pub struct Dungeon { pub floor: Floor, pub player: Player, @@ -46,6 +46,12 @@ impl Dungeon { pub fn new_seeded(seed: u64) -> Self { Self::from(Floor::generate_seeded(seed)) } + + /// Returns the current position of the camera (viewer) + #[must_use] + pub fn camera(&self) -> FPos { + self.player.entity.fpos + } } impl Default for Dungeon { fn default() -> Self { 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) + } +} |