mirror of
https://github.com/Xevion/Pac-Man.git
synced 2025-12-06 11:15:46 -06:00
feat: add bottom row HUD, proper life display sprites
This commit is contained in:
2
Cargo.lock
generated
2
Cargo.lock
generated
@@ -663,7 +663,7 @@ checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pacman"
|
name = "pacman"
|
||||||
version = "0.78.0"
|
version = "0.78.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"bevy_ecs",
|
"bevy_ecs",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "pacman"
|
name = "pacman"
|
||||||
version = "0.78.0"
|
version = "0.78.1"
|
||||||
authors = ["Xevion"]
|
authors = ["Xevion"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
rust-version = "1.86.0"
|
rust-version = "1.86.0"
|
||||||
|
|||||||
@@ -25,12 +25,25 @@ pub const SCALE: f32 = 2.6;
|
|||||||
/// screen for score display, player lives, and other UI elements.
|
/// screen for score display, player lives, and other UI elements.
|
||||||
pub const BOARD_CELL_OFFSET: UVec2 = UVec2::new(0, 3);
|
pub const BOARD_CELL_OFFSET: UVec2 = UVec2::new(0, 3);
|
||||||
|
|
||||||
|
/// Bottom HUD row offset to reserve space below the game board.
|
||||||
|
///
|
||||||
|
/// The 2-cell vertical offset (16 pixels) provides space at the bottom of the
|
||||||
|
/// screen for displaying Pac-Man's lives (left) and fruit symbols (right).
|
||||||
|
pub const BOARD_BOTTOM_CELL_OFFSET: UVec2 = UVec2::new(0, 2);
|
||||||
|
|
||||||
/// Pixel-space equivalent of `BOARD_CELL_OFFSET` for rendering calculations.
|
/// Pixel-space equivalent of `BOARD_CELL_OFFSET` for rendering calculations.
|
||||||
///
|
///
|
||||||
/// Automatically calculated from the cell offset to maintain consistency
|
/// Automatically calculated from the cell offset to maintain consistency
|
||||||
/// when the cell size changes. Used for positioning sprites and debug overlays.
|
/// when the cell size changes. Used for positioning sprites and debug overlays.
|
||||||
pub const BOARD_PIXEL_OFFSET: UVec2 = UVec2::new(BOARD_CELL_OFFSET.x * CELL_SIZE, BOARD_CELL_OFFSET.y * CELL_SIZE);
|
pub const BOARD_PIXEL_OFFSET: UVec2 = UVec2::new(BOARD_CELL_OFFSET.x * CELL_SIZE, BOARD_CELL_OFFSET.y * CELL_SIZE);
|
||||||
|
|
||||||
|
/// Pixel-space equivalent of `BOARD_BOTTOM_CELL_OFFSET` for rendering calculations.
|
||||||
|
///
|
||||||
|
/// Automatically calculated from the cell offset to maintain consistency
|
||||||
|
/// when the cell size changes. Used for positioning bottom HUD elements.
|
||||||
|
pub const BOARD_BOTTOM_PIXEL_OFFSET: UVec2 =
|
||||||
|
UVec2::new(BOARD_BOTTOM_CELL_OFFSET.x * CELL_SIZE, BOARD_BOTTOM_CELL_OFFSET.y * CELL_SIZE);
|
||||||
|
|
||||||
/// Animation timing constants for ghost state management
|
/// Animation timing constants for ghost state management
|
||||||
pub mod animation {
|
pub mod animation {
|
||||||
/// Normal ghost movement animation speed (ticks per frame at 60 ticks/sec)
|
/// Normal ghost movement animation speed (ticks per frame at 60 ticks/sec)
|
||||||
@@ -45,15 +58,15 @@ pub mod animation {
|
|||||||
}
|
}
|
||||||
/// The size of the canvas, in pixels.
|
/// The size of the canvas, in pixels.
|
||||||
pub const CANVAS_SIZE: UVec2 = UVec2::new(
|
pub const CANVAS_SIZE: UVec2 = UVec2::new(
|
||||||
(BOARD_CELL_SIZE.x + BOARD_CELL_OFFSET.x) * CELL_SIZE,
|
(BOARD_CELL_SIZE.x + BOARD_CELL_OFFSET.x + BOARD_BOTTOM_CELL_OFFSET.x) * CELL_SIZE,
|
||||||
(BOARD_CELL_SIZE.y + BOARD_CELL_OFFSET.y) * CELL_SIZE,
|
(BOARD_CELL_SIZE.y + BOARD_CELL_OFFSET.y + BOARD_BOTTOM_CELL_OFFSET.y) * CELL_SIZE,
|
||||||
);
|
);
|
||||||
|
|
||||||
pub const LARGE_SCALE: f32 = 2.6;
|
pub const LARGE_SCALE: f32 = 2.6;
|
||||||
|
|
||||||
pub const LARGE_CANVAS_SIZE: UVec2 = UVec2::new(
|
pub const LARGE_CANVAS_SIZE: UVec2 = UVec2::new(
|
||||||
(((BOARD_CELL_SIZE.x + BOARD_CELL_OFFSET.x) * CELL_SIZE) as f32 * LARGE_SCALE) as u32,
|
(((BOARD_CELL_SIZE.x + BOARD_CELL_OFFSET.x + BOARD_BOTTOM_CELL_OFFSET.x) * CELL_SIZE) as f32 * LARGE_SCALE) as u32,
|
||||||
(((BOARD_CELL_SIZE.y + BOARD_CELL_OFFSET.y) * CELL_SIZE) as f32 * LARGE_SCALE) as u32,
|
(((BOARD_CELL_SIZE.y + BOARD_CELL_OFFSET.y + BOARD_BOTTOM_CELL_OFFSET.y) * CELL_SIZE) as f32 * LARGE_SCALE) as u32,
|
||||||
);
|
);
|
||||||
|
|
||||||
/// Collider size constants for different entity types
|
/// Collider size constants for different entity types
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
use crate::map::builder::Map;
|
use crate::map::builder::Map;
|
||||||
|
use crate::map::direction::Direction;
|
||||||
use crate::systems::input::TouchState;
|
use crate::systems::input::TouchState;
|
||||||
use crate::systems::{
|
use crate::systems::{
|
||||||
debug_render_system, BatchedLinesResource, Collider, CursorPosition, DebugState, DebugTextureResource, DeltaTime,
|
debug_render_system, BatchedLinesResource, Collider, CursorPosition, DebugState, DebugTextureResource, DeltaTime,
|
||||||
@@ -6,9 +7,10 @@ use crate::systems::{
|
|||||||
StartupSequence, SystemId, SystemTimings, TtfAtlasResource, Velocity,
|
StartupSequence, SystemId, SystemTimings, TtfAtlasResource, Velocity,
|
||||||
};
|
};
|
||||||
use crate::texture::sprite::SpriteAtlas;
|
use crate::texture::sprite::SpriteAtlas;
|
||||||
|
use crate::texture::sprites::{GameSprite, PacmanSprite};
|
||||||
use crate::texture::text::TextTexture;
|
use crate::texture::text::TextTexture;
|
||||||
use crate::{
|
use crate::{
|
||||||
constants::CANVAS_SIZE,
|
constants::{BOARD_BOTTOM_PIXEL_OFFSET, CANVAS_SIZE, CELL_SIZE},
|
||||||
error::{GameError, TextureError},
|
error::{GameError, TextureError},
|
||||||
};
|
};
|
||||||
use bevy_ecs::component::Component;
|
use bevy_ecs::component::Component;
|
||||||
@@ -218,14 +220,42 @@ pub fn hud_render_system(
|
|||||||
let mut text_renderer = TextTexture::new(1.0);
|
let mut text_renderer = TextTexture::new(1.0);
|
||||||
|
|
||||||
// Render lives and high score text in white
|
// Render lives and high score text in white
|
||||||
let lives = player_lives.0;
|
let lives_text = "1UP HIGH SCORE ";
|
||||||
let lives_text = format!("{lives}UP HIGH SCORE ");
|
|
||||||
let lives_position = glam::UVec2::new(4 + 8 * 3, 2); // x_offset + lives_offset * 8, y_offset
|
let lives_position = glam::UVec2::new(4 + 8 * 3, 2); // x_offset + lives_offset * 8, y_offset
|
||||||
|
|
||||||
if let Err(e) = text_renderer.render(canvas, &mut atlas, &lives_text, lives_position) {
|
if let Err(e) = text_renderer.render(canvas, &mut atlas, lives_text, lives_position) {
|
||||||
errors.write(TextureError::RenderFailed(format!("Failed to render lives text: {}", e)).into());
|
errors.write(TextureError::RenderFailed(format!("Failed to render lives text: {}", e)).into());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Render Pac-Man life sprites in bottom left
|
||||||
|
let lives = player_lives.0;
|
||||||
|
let life_sprite_path = &GameSprite::Pacman(PacmanSprite::Moving(Direction::Left, 1)).to_path();
|
||||||
|
|
||||||
|
// Get the sprite from the atlas for life display
|
||||||
|
match atlas.get_tile(life_sprite_path) {
|
||||||
|
Ok(life_sprite) => {
|
||||||
|
let start_x = CELL_SIZE * 2; // 2 cells from left
|
||||||
|
let start_y = CANVAS_SIZE.y - BOARD_BOTTOM_PIXEL_OFFSET.y + (CELL_SIZE / 2) + 1; // In bottom area
|
||||||
|
let sprite_spacing = CELL_SIZE + CELL_SIZE / 2; // 1.5 cells between sprites
|
||||||
|
|
||||||
|
// Render one sprite for each remaining life (lives - 1, since current life isn't shown)
|
||||||
|
let sprites_to_show = if lives > 0 { lives - 1 } else { 0 };
|
||||||
|
for i in 0..sprites_to_show {
|
||||||
|
let x = start_x + ((i as f32) * (sprite_spacing as f32 * 1.5)).round() as u32;
|
||||||
|
let y = start_y - CELL_SIZE / 2;
|
||||||
|
|
||||||
|
let dest = sdl2::rect::Rect::new(x as i32, y as i32, life_sprite.size.x as u32, life_sprite.size.y as u32);
|
||||||
|
|
||||||
|
if let Err(e) = life_sprite.render(canvas, &mut atlas, dest) {
|
||||||
|
errors.write(TextureError::RenderFailed(format!("Failed to render life sprite: {}", e)).into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
errors.write(e.into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Render score text
|
// Render score text
|
||||||
let score_text = format!("{:02}", score.0);
|
let score_text = format!("{:02}", score.0);
|
||||||
let score_offset = 7 - (score_text.len() as i32);
|
let score_offset = 7 - (score_text.len() as i32);
|
||||||
|
|||||||
Reference in New Issue
Block a user