diff options
| -rw-r--r-- | assets/atlas.bmp | bin | 65674 -> 65674 bytes | |||
| -rw-r--r-- | assets/error.bmp | bin | 0 -> 4234 bytes | |||
| -rw-r--r-- | assets/heart_empty.bmp | bin | 0 -> 4234 bytes | |||
| -rw-r--r-- | assets/heart_full.bmp | bin | 0 -> 4234 bytes | |||
| -rw-r--r-- | assets/heart_half.bmp | bin | 0 -> 4234 bytes | |||
| -rw-r--r-- | dungeon/src/entity.rs | 10 | ||||
| -rw-r--r-- | graphics/src/assets.rs | 26 | ||||
| -rw-r--r-- | graphics/src/render.rs | 141 |
8 files changed, 162 insertions, 15 deletions
diff --git a/assets/atlas.bmp b/assets/atlas.bmp Binary files differindex db3fac4..a1f6f9a 100644 --- a/assets/atlas.bmp +++ b/assets/atlas.bmp diff --git a/assets/error.bmp b/assets/error.bmp Binary files differnew file mode 100644 index 0000000..051849c --- /dev/null +++ b/assets/error.bmp diff --git a/assets/heart_empty.bmp b/assets/heart_empty.bmp Binary files differnew file mode 100644 index 0000000..d59d841 --- /dev/null +++ b/assets/heart_empty.bmp diff --git a/assets/heart_full.bmp b/assets/heart_full.bmp Binary files differnew file mode 100644 index 0000000..bacb7f0 --- /dev/null +++ b/assets/heart_full.bmp diff --git a/assets/heart_half.bmp b/assets/heart_half.bmp Binary files differnew file mode 100644 index 0000000..6ab617d --- /dev/null +++ b/assets/heart_half.bmp 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 { |