summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--assets/atlas.bmpbin65674 -> 65674 bytes
-rw-r--r--assets/error.bmpbin0 -> 4234 bytes
-rw-r--r--assets/heart_empty.bmpbin0 -> 4234 bytes
-rw-r--r--assets/heart_full.bmpbin0 -> 4234 bytes
-rw-r--r--assets/heart_half.bmpbin0 -> 4234 bytes
-rw-r--r--dungeon/src/entity.rs10
-rw-r--r--graphics/src/assets.rs26
-rw-r--r--graphics/src/render.rs141
8 files changed, 162 insertions, 15 deletions
diff --git a/assets/atlas.bmp b/assets/atlas.bmp
index db3fac4..a1f6f9a 100644
--- a/assets/atlas.bmp
+++ b/assets/atlas.bmp
Binary files differ
diff --git a/assets/error.bmp b/assets/error.bmp
new file mode 100644
index 0000000..051849c
--- /dev/null
+++ b/assets/error.bmp
Binary files differ
diff --git a/assets/heart_empty.bmp b/assets/heart_empty.bmp
new file mode 100644
index 0000000..d59d841
--- /dev/null
+++ b/assets/heart_empty.bmp
Binary files differ
diff --git a/assets/heart_full.bmp b/assets/heart_full.bmp
new file mode 100644
index 0000000..bacb7f0
--- /dev/null
+++ b/assets/heart_full.bmp
Binary files differ
diff --git a/assets/heart_half.bmp b/assets/heart_half.bmp
new file mode 100644
index 0000000..6ab617d
--- /dev/null
+++ b/assets/heart_half.bmp
Binary files differ
diff --git a/dungeon/src/entity.rs b/dungeon/src/entity.rs
index 4ea6725..02184a9 100644
--- a/dungeon/src/entity.rs
+++ b/dungeon/src/entity.rs
@@ -2,6 +2,12 @@
use crate::{Direction, FPos, Pos, const_pos};
+/// `PLAYER_FULL_HEALTH` is the starting health of the player entity
+pub const PLAYER_FULL_HEALTH: u32 = 10;
+
+/// `PLAYER_INVENTORY_SIZE` is the maximum size of the inventory
+pub const PLAYER_INVENTORY_SIZE: usize = 5;
+
/// The `Item` type represents any item an entity may be using
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum Item {
@@ -46,7 +52,7 @@ impl Entity {
/// let pos = Pos::new(0, 0).unwrap();
/// let dir = Direction::North;
/// let kind = EntityKind::Player;
- /// let health = Some(100);
+ /// let health = Some(10);
/// let entity = Entity::new(pos, dir, kind, health);
/// ```
#[must_use]
@@ -80,7 +86,7 @@ impl Entity {
pub const fn player(pos: Pos) -> Self {
let dir = Direction::East;
let kind = EntityKind::Player;
- let health = Some(100);
+ let health = Some(PLAYER_FULL_HEALTH);
Self::new(pos, dir, kind, health)
}
}
diff --git a/graphics/src/assets.rs b/graphics/src/assets.rs
index e607fdf..bb989a3 100644
--- a/graphics/src/assets.rs
+++ b/graphics/src/assets.rs
@@ -1,6 +1,7 @@
//! The `assets` crate stores all audio and image assets that need to be
//! loaded during runtime
+use dungeon::Item;
use raylib::{RaylibHandle, RaylibThread, audio::RaylibAudio, texture::Texture2D};
#[expect(dead_code)]
@@ -50,6 +51,8 @@ pub(crate) enum AtlasTexture {
WallEdgeSouth,
WallEdgeWest,
Player,
+ InvTopLayer,
+ InvBottomLayer,
Error,
}
impl AtlasTexture {
@@ -66,6 +69,8 @@ impl AtlasTexture {
Self::WallEdgeSouth => (2, 1),
Self::WallEdgeWest => (3, 1),
Self::Player => (0, 2),
+ Self::InvTopLayer => (1, 2),
+ Self::InvBottomLayer => (2, 2),
Self::Error => (3, 3),
}
}
@@ -87,6 +92,10 @@ impl AtlasTexture {
#[derive(Debug)]
pub(crate) struct ImageData {
pub(crate) atlas: Texture2D,
+ pub(crate) heart_full: Texture2D,
+ pub(crate) heart_half: Texture2D,
+ pub(crate) heart_empty: Texture2D,
+ pub(crate) error: Texture2D,
}
impl ImageData {
pub(crate) fn load(
@@ -94,7 +103,22 @@ impl ImageData {
thread: &RaylibThread,
) -> crate::Result<Self> {
let atlas = handle.load_texture(thread, "assets/atlas.bmp")?;
+ let heart_full = handle.load_texture(thread, "assets/heart_full.bmp")?;
+ let heart_half = handle.load_texture(thread, "assets/heart_half.bmp")?;
+ let heart_empty = handle.load_texture(thread, "assets/heart_empty.bmp")?;
+ let error = handle.load_texture(thread, "assets/error.bmp")?;
- Ok(Self { atlas })
+ Ok(Self {
+ atlas,
+ heart_full,
+ heart_half,
+ heart_empty,
+ error,
+ })
+ }
+
+ pub(crate) fn get_item_texture(&self, _item: &Item) -> &Texture2D {
+ // TODO: make item textures
+ &self.error
}
}
diff --git a/graphics/src/render.rs b/graphics/src/render.rs
index b6af7c7..499301c 100644
--- a/graphics/src/render.rs
+++ b/graphics/src/render.rs
@@ -2,12 +2,12 @@
//! the game, with each frame represented by a `Renderer` and
//! frame specific information in `FrameInfo`.
-/// The (prefered) view distance of the game
-const VIEW_DISTANCE: i32 = 5;
-
use std::{cell::RefCell, ops::Div, rc::Rc};
-use dungeon::{Direction, Dungeon, Entity, EntityKind, FPos, Floor, MAP_SIZE, Pos, Tile};
+use dungeon::{
+ Direction, Dungeon, Entity, EntityKind, FPos, Floor, MAP_SIZE, PLAYER_FULL_HEALTH,
+ Player, Pos, Tile,
+};
use raylib::{
RaylibThread,
camera::Camera2D,
@@ -22,6 +22,17 @@ use raylib::{
use crate::assets::{AtlasTexture, BASE_TILE_SIZE, ImageData, WALL_HEIGHT};
+/// The (prefered) view distance of the game
+const VIEW_DISTANCE: i32 = 5;
+
+/// Full source rec for any texture
+const FULL_SOURCE_REC: Rectangle = Rectangle {
+ x: 0.0,
+ y: 0.0,
+ width: BASE_TILE_SIZE as f32,
+ height: BASE_TILE_SIZE as f32,
+};
+
/// The `FrameInfo` struct stores information used during a single frame
#[derive(Clone, Copy, Debug)]
struct FrameInfo {
@@ -285,12 +296,118 @@ where
}
/// Draws player HP, inventory, and floor number
- pub fn draw_ui(&mut self, _dungeon: &Dungeon) {
+ pub fn draw_ui(&mut self, dungeon: &Dungeon) {
+ // Draw core ui components
+ self.draw_health(&dungeon.player);
+ self.draw_inventory(&dungeon.player);
+
+ // Draw debug info
#[cfg(feature = "debug")]
- // Draw fps (debug only)
+ self.draw_debug_ui(dungeon);
+ }
+
+ fn draw_health(&mut self, player: &Player) {
+ let health = player.entity.health.unwrap_or(0);
+ let hearts = PLAYER_FULL_HEALTH.div_ceil(2);
+ let mut full_hearts = health / 2;
+ let mut half_hearts = health % 2;
+ let mut empty_hearts = hearts.saturating_sub(full_hearts + half_hearts);
+
+ let size = self.info.tile_size.div(2).max(BASE_TILE_SIZE);
+ let y = BASE_TILE_SIZE;
+ let mut x = BASE_TILE_SIZE;
+ loop {
+ let tex = if full_hearts > 0 {
+ full_hearts -= 1;
+ &self.state.image.heart_full
+ } else if half_hearts > 0 {
+ half_hearts -= 1;
+ &self.state.image.heart_half
+ } else if empty_hearts > 0 {
+ empty_hearts -= 1;
+ &self.state.image.heart_empty
+ } else {
+ break;
+ };
+
+ let dest_rec = Rectangle {
+ x: x as f32,
+ y: y as f32,
+ width: size as f32,
+ height: size as f32,
+ };
+ self.handle.draw_texture_pro(
+ tex,
+ FULL_SOURCE_REC,
+ dest_rec,
+ Vector2::zero(),
+ 0.0,
+ Color::WHITE,
+ );
+ x += size;
+ }
+ }
+
+ fn draw_inventory(&mut self, player: &Player) {
+ let len = i32::try_from(player.inventory.len()).unwrap_or(0);
+
+ // size of the inv blocks
+ let size = self.info.tile_size.div(2).max(BASE_TILE_SIZE);
+
+ // position of the inv blocks
+ let y = self.info.height - size;
+ let mut x = self.info.width / 2 - (size * len / 2);
+
+ // size of font for number index
+ let font_size = size / 3;
+ let font_offset = font_size * 2;
+
+ for (idx, item) in player.inventory.iter().enumerate() {
+ let dest_rec = Rectangle {
+ x: x as f32,
+ y: y as f32,
+ width: size as f32,
+ height: size as f32,
+ };
+ self.draw_ui_atlas(
+ AtlasTexture::InvBottomLayer,
+ x as f32,
+ y as f32,
+ size as f32,
+ );
+ let tex = self.state.image.get_item_texture(item);
+ self.handle.draw_texture_pro(
+ tex,
+ FULL_SOURCE_REC,
+ dest_rec,
+ Vector2::zero(),
+ 0.0,
+ Color::WHITE,
+ );
+ self.draw_ui_atlas(AtlasTexture::InvTopLayer, x as f32, y as f32, size as f32);
+ self.handle.draw_text(
+ &format!("{}", idx + 1),
+ x + font_offset + font_offset / 5,
+ y + font_offset,
+ font_size,
+ Color::WHITE,
+ );
+ x += size;
+ }
+ }
+
+ /// Draws debug information ontop of other UI elements
+ /// Called by default if `debug` featue is enabled
+ pub fn draw_debug_ui(&mut self, _dungeon: &Dungeon) {
self.draw_fps();
}
+ /// Draw FPS counter (debug)
+ fn draw_fps(&mut self) {
+ let fps_str = format!("{}", self.info.fps);
+ self.handle.draw_text(&fps_str, 10, 10, 30, Color::YELLOW);
+ }
+
/// Draws the entities on the map
fn draw_entities(&mut self, dungeon: &Dungeon) {
self.draw_entity(&dungeon.player.entity);
@@ -324,6 +441,12 @@ where
self.handle.draw_tilemap(tex, size, offset);
}
+ /// Draw an atlas texture index (with ui offset applied)
+ fn draw_ui_atlas(&mut self, tex: AtlasTexture, x: f32, y: f32, size: f32) {
+ let half_size = size / 2.0;
+ self.draw_atlas(tex, x + half_size, y + half_size, size, 0.0);
+ }
+
/// Draw an atlas texture index
fn draw_atlas(&mut self, tex: AtlasTexture, x: f32, y: f32, size: f32, rotation: f32) {
let source_rec = Rectangle {
@@ -351,12 +474,6 @@ where
Color::WHITE,
);
}
-
- /// Draw FPS counter
- fn draw_fps(&mut self) {
- let fps_str = format!("{}", self.info.fps);
- self.handle.draw_text(&fps_str, 10, 10, 30, Color::YELLOW);
- }
}
trait Vector2Ext {