summaryrefslogtreecommitdiff
path: root/dungeon
diff options
context:
space:
mode:
authorFreya Murphy <freya@freyacat.org>2025-10-23 13:08:40 -0400
committerFreya Murphy <freya@freyacat.org>2025-10-23 13:10:19 -0400
commit0c3e9c8dc49ff11d7612bd7e0bc25030ae566ab1 (patch)
treee286028ebb74c5ffd08433dd8ff25d6149b68afc /dungeon
parentStarted implementing wfc crate into map (diff)
downloadDungeonCrawl-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.rs10
-rw-r--r--dungeon/src/lib.rs8
-rw-r--r--dungeon/src/pos.rs142
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)
+ }
+}