From 7a6182cb8567235aad8cf3b1f348ed666acc13bd Mon Sep 17 00:00:00 2001 From: Xevion Date: Sat, 26 Jul 2025 15:26:37 -0500 Subject: [PATCH] feat: re-add board offset logic, fixup text rendering --- src/constants.rs | 9 ++++++++- src/entity/edible.rs | 4 ++-- src/entity/mod.rs | 6 +++--- src/game.rs | 20 ++++++++++---------- src/main.rs | 12 ++++++------ src/map.rs | 14 +++++++++++--- src/texture/animated.rs | 4 ++-- src/texture/text.rs | 1 - 8 files changed, 42 insertions(+), 28 deletions(-) diff --git a/src/constants.rs b/src/constants.rs index 9318b1a..f558458 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -11,9 +11,16 @@ pub const BOARD_CELL_SIZE: UVec2 = UVec2::new(28, 31); pub const SCALE: f32 = 2.6; /// The offset of the game board from the top-left corner of the window, in cells. -pub const BOARD_OFFSET: UVec2 = UVec2::new(0, 0); +pub const BOARD_CELL_OFFSET: UVec2 = UVec2::new(0, 3); +/// The offset of the game board from the top-left corner of the window, in pixels. +pub const BOARD_PIXEL_OFFSET: UVec2 = UVec2::new(BOARD_CELL_OFFSET.x * CELL_SIZE, BOARD_CELL_OFFSET.y * CELL_SIZE); /// The size of the game board, in pixels. pub const BOARD_PIXEL_SIZE: UVec2 = UVec2::new(BOARD_CELL_SIZE.x * CELL_SIZE, BOARD_CELL_SIZE.y * CELL_SIZE); +/// The size of the canvas, in pixels. +pub const CANVAS_SIZE: UVec2 = UVec2::new( + (BOARD_CELL_SIZE.x + BOARD_CELL_OFFSET.x) * CELL_SIZE, + (BOARD_CELL_SIZE.y + BOARD_CELL_OFFSET.y) * CELL_SIZE, +); /// An enum representing the different types of tiles on the map. #[derive(Debug, Clone, Copy, PartialEq)] diff --git a/src/entity/edible.rs b/src/entity/edible.rs index 1a45833..b5360a2 100644 --- a/src/entity/edible.rs +++ b/src/entity/edible.rs @@ -63,13 +63,13 @@ impl Renderable for Edible { let pos = self.base.pixel_position; let dest = match &mut self.sprite { EdibleSprite::Pellet(sprite) => { - let mut tile = sprite.current_tile(); + let tile = sprite.current_tile(); let x = pos.x + ((crate::constants::CELL_SIZE as i32 - tile.size.x as i32) / 2); let y = pos.y + ((crate::constants::CELL_SIZE as i32 - tile.size.y as i32) / 2); sdl2::rect::Rect::new(x, y, tile.size.x as u32, tile.size.y as u32) } EdibleSprite::PowerPellet(sprite) => { - let mut tile = sprite.animation.current_tile(); + let tile = sprite.animation.current_tile(); let x = pos.x + ((crate::constants::CELL_SIZE as i32 - tile.size.x as i32) / 2); let y = pos.y + ((crate::constants::CELL_SIZE as i32 - tile.size.y as i32) / 2); sdl2::rect::Rect::new(x, y, tile.size.x as u32, tile.size.y as u32) diff --git a/src/entity/mod.rs b/src/entity/mod.rs index df33381..7f0b881 100644 --- a/src/entity/mod.rs +++ b/src/entity/mod.rs @@ -6,7 +6,7 @@ pub mod pacman; pub mod speed; use crate::{ - constants::{MapTile, BOARD_CELL_SIZE, BOARD_OFFSET, CELL_SIZE}, + constants::{MapTile, BOARD_CELL_OFFSET, BOARD_CELL_SIZE, CELL_SIZE}, entity::{direction::Direction, speed::SimpleTickModulator}, map::Map, }; @@ -145,8 +145,8 @@ impl Moving for MovableEntity { } fn update_cell_position(&mut self) { self.base.cell_position = UVec2::new( - (self.base.pixel_position.x as u32 / CELL_SIZE) - BOARD_OFFSET.x, - (self.base.pixel_position.y as u32 / CELL_SIZE) - BOARD_OFFSET.y, + (self.base.pixel_position.x as u32 / CELL_SIZE) - BOARD_CELL_OFFSET.x, + (self.base.pixel_position.y as u32 / CELL_SIZE) - BOARD_CELL_OFFSET.y, ); } fn next_cell(&self, direction: Option) -> IVec2 { diff --git a/src/game.rs b/src/game.rs index c539b45..ace8802 100644 --- a/src/game.rs +++ b/src/game.rs @@ -4,12 +4,13 @@ use std::ops::Not; use std::rc::Rc; use anyhow::Result; -use glam::{IVec2, UVec2}; +use glam::UVec2; use rand::rngs::SmallRng; use rand::seq::IteratorRandom; use rand::SeedableRng; use sdl2::image::LoadTexture; use sdl2::keyboard::Keycode; + use sdl2::render::{Texture, TextureCreator}; use sdl2::video::WindowContext; use sdl2::{pixels::Color, render::Canvas, video::Window}; @@ -268,7 +269,6 @@ impl Game { } let _ = this.pacman.borrow_mut().render(texture_canvas); let _ = this.blinky.render(texture_canvas); - this.render_ui_on(texture_canvas); match this.debug_mode { DebugMode::Grid => { DebugRenderer::draw_debug_grid( @@ -290,10 +290,11 @@ impl Game { }) .map_err(|e| anyhow::anyhow!(format!("Failed to render to backbuffer: {e}"))) } - pub fn present_backbuffer(&self, canvas: &mut Canvas, backbuffer: &Texture) -> Result<()> { + pub fn present_backbuffer(&mut self, canvas: &mut Canvas, backbuffer: &Texture) -> Result<()> { canvas.set_draw_color(Color::BLACK); canvas.clear(); canvas.copy(backbuffer, None, None).map_err(anyhow::Error::msg)?; + self.render_ui_on(canvas); canvas.present(); Ok(()) } @@ -301,22 +302,21 @@ impl Game { fn render_ui_on(&mut self, canvas: &mut sdl2::render::Canvas) { let lives = 3; let score_text = format!("{:02}", self.score); - let x_offset = 12; + let x_offset = 4; let y_offset = 2; let lives_offset = 3; let score_offset = 7 - (score_text.len() as i32); - let gap_offset = 6; - self.text_texture.set_scale(2.0); - self.text_texture.render( + self.text_texture.set_scale(1.0); + let _ = self.text_texture.render( canvas, &format!("{lives}UP HIGH SCORE "), - UVec2::new(24 * lives_offset as u32 + x_offset, y_offset), + UVec2::new(8 * lives_offset as u32 + x_offset, y_offset), Color::WHITE, ); - self.text_texture.render( + let _ = self.text_texture.render( canvas, &score_text, - UVec2::new(24 * score_offset as u32 + x_offset, 24 + y_offset + gap_offset), + UVec2::new(8 * score_offset as u32 + x_offset, 8 + y_offset), Color::WHITE, ); diff --git a/src/main.rs b/src/main.rs index 3c44c18..437993b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,6 @@ #![windows_subsystem = "windows"] -use crate::constants::{BOARD_PIXEL_SIZE, SCALE}; +use crate::constants::{CANVAS_SIZE, SCALE}; use crate::game::Game; use sdl2::event::{Event, WindowEvent}; use sdl2::keyboard::Keycode; @@ -105,8 +105,8 @@ pub fn main() { let window = video_subsystem .window( "Pac-Man", - (BOARD_PIXEL_SIZE.x as f32 * SCALE).round() as u32, - (BOARD_PIXEL_SIZE.y as f32 * SCALE).round() as u32, + (CANVAS_SIZE.x as f32 * SCALE).round() as u32, + (CANVAS_SIZE.y as f32 * SCALE).round() as u32, ) .resizable() .position_centered() @@ -116,7 +116,7 @@ pub fn main() { let mut canvas = window.into_canvas().build().expect("Could not build canvas"); canvas - .set_logical_size(BOARD_PIXEL_SIZE.x, BOARD_PIXEL_SIZE.y) + .set_logical_size(CANVAS_SIZE.x, CANVAS_SIZE.y) .expect("Could not set logical size"); let texture_creator = canvas.texture_creator(); @@ -127,7 +127,7 @@ pub fn main() { // Create a backbuffer texture for drawing let mut backbuffer = texture_creator_static - .create_texture_target(None, BOARD_PIXEL_SIZE.x, BOARD_PIXEL_SIZE.y) + .create_texture_target(None, CANVAS_SIZE.x, CANVAS_SIZE.y) .expect("Could not create backbuffer texture"); let mut event_pump = sdl_context.event_pump().expect("Could not get SDL EventPump"); @@ -154,7 +154,7 @@ pub fn main() { let mut last_frame_time = Instant::now(); event!(tracing::Level::INFO, "Starting game loop ({:?})", loop_time); - let mut main_loop = || { + let mut main_loop = move || { let start = Instant::now(); let current_frame_time = Instant::now(); let frame_duration = current_frame_time.duration_since(last_frame_time); diff --git a/src/map.rs b/src/map.rs index 28e7064..5a226f8 100644 --- a/src/map.rs +++ b/src/map.rs @@ -3,7 +3,7 @@ use rand::rngs::SmallRng; use rand::seq::IteratorRandom; use rand::SeedableRng; -use crate::constants::{MapTile, BOARD_CELL_SIZE, BOARD_OFFSET, CELL_SIZE}; +use crate::constants::{MapTile, BOARD_CELL_OFFSET, BOARD_CELL_SIZE, BOARD_PIXEL_OFFSET, BOARD_PIXEL_SIZE, CELL_SIZE}; use crate::texture::sprite::AtlasTile; use glam::{IVec2, UVec2}; use once_cell::sync::OnceCell; @@ -104,7 +104,10 @@ impl Map { /// /// * `cell` - The cell coordinates, in grid coordinates. pub fn cell_to_pixel(cell: UVec2) -> IVec2 { - IVec2::new((cell.x * CELL_SIZE) as i32, ((cell.y + BOARD_OFFSET.y) * CELL_SIZE) as i32) + IVec2::new( + (cell.x * CELL_SIZE) as i32, + ((cell.y + BOARD_CELL_OFFSET.y) * CELL_SIZE) as i32, + ) } /// Returns a reference to a cached vector of all valid playable positions in the maze. @@ -162,7 +165,12 @@ impl Map { /// Renders the map to the given canvas using the provided map texture. pub fn render(&self, canvas: &mut Canvas, map_texture: &mut AtlasTile) { - let dest = Rect::new(0, 0, CELL_SIZE * BOARD_CELL_SIZE.x, CELL_SIZE * BOARD_CELL_SIZE.y); + let dest = Rect::new( + BOARD_PIXEL_OFFSET.x as i32, + BOARD_PIXEL_OFFSET.y as i32, + BOARD_PIXEL_SIZE.x, + BOARD_PIXEL_SIZE.y, + ); let _ = map_texture.render(canvas, dest); } } diff --git a/src/texture/animated.rs b/src/texture/animated.rs index 40229a9..2437ede 100644 --- a/src/texture/animated.rs +++ b/src/texture/animated.rs @@ -1,6 +1,6 @@ //! This module provides a simple animation and atlas system for textures. use anyhow::Result; -use sdl2::{pixels::Color, render::WindowCanvas}; +use sdl2::render::WindowCanvas; use crate::texture::sprite::AtlasTile; @@ -43,7 +43,7 @@ impl AnimatedTexture { } pub fn render(&mut self, canvas: &mut WindowCanvas, dest: sdl2::rect::Rect) -> Result<()> { - let mut tile = self.current_tile(); + let tile = self.current_tile(); tile.render(canvas, dest) } } diff --git a/src/texture/text.rs b/src/texture/text.rs index 5aa1586..8d26b72 100644 --- a/src/texture/text.rs +++ b/src/texture/text.rs @@ -49,7 +49,6 @@ use anyhow::Result; use glam::UVec2; use sdl2::pixels::Color; -use sdl2::rect::Rect; use sdl2::render::{Canvas, RenderTarget}; use std::cell::RefCell; use std::collections::HashMap;