diff --git a/src/constants.rs b/src/constants.rs index 2f7075a..f33b839 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -1,11 +1,11 @@ -use lazy_static::lazy_static; - pub const BOARD_WIDTH: u32 = 28; -pub const BOARD_HEIGHT: u32 = 37; // Adjusted to fit map texture? +pub const BOARD_HEIGHT: u32 = 31; // Adjusted to fit map texture? pub const CELL_SIZE: u32 = 24; +pub const BOARD_OFFSET: (u32, u32) = (0, 3); // Relative cell offset for where map text / grid starts + pub const WINDOW_WIDTH: u32 = CELL_SIZE * BOARD_WIDTH; -pub const WINDOW_HEIGHT: u32 = CELL_SIZE * BOARD_HEIGHT; +pub const WINDOW_HEIGHT: u32 = CELL_SIZE * (BOARD_HEIGHT + 6); // Map texture is 6 cells taller (3 above, 3 below) than the grid #[derive(Debug, Copy, Clone, PartialEq)] pub enum MapTile { @@ -17,9 +17,6 @@ pub enum MapTile { } pub const RAW_BOARD: [&str; BOARD_HEIGHT as usize] = [ - " ", - " ", - " ", "############################", "#............##............#", "#.####.#####.##.#####.####.#", @@ -51,45 +48,4 @@ pub const RAW_BOARD: [&str; BOARD_HEIGHT as usize] = [ "#.##########.##.##########.#", "#..........................#", "############################", - " ", - " ", - " ", -]; - -lazy_static! { - pub static ref BOARD: [[MapTile; BOARD_HEIGHT as usize]; BOARD_HEIGHT as usize] = { - let mut board = [[MapTile::Empty; BOARD_HEIGHT as usize]; BOARD_HEIGHT as usize]; - - for y in 0..BOARD_HEIGHT as usize { - let line = RAW_BOARD[y]; - - for x in 0..BOARD_WIDTH as usize { - if x >= line.len() { - break; - } - - let i = (y * (BOARD_WIDTH as usize) + x) as usize; - let character = line - .chars() - .nth(x as usize) - .unwrap_or_else(|| panic!("Could not get character at {} = ({}, {})", i, x, y)); - - let tile = match character { - '#' => MapTile::Wall, - '.' => MapTile::Pellet, - 'o' => MapTile::PowerPellet, - ' ' => MapTile::Empty, - c @ '0' | c @ '1' | c @ '2' | c @ '3' | c @ '4' => { - MapTile::StartingPosition(c.to_digit(10).unwrap() as u8) - }, - '=' => MapTile::Empty, - _ => panic!("Unknown character in board: {}", character), - }; - - board[x as usize][y as usize] = tile; - } - } - - board - }; -} +]; \ No newline at end of file diff --git a/src/game.rs b/src/game.rs index b4e95a7..5c865b1 100644 --- a/src/game.rs +++ b/src/game.rs @@ -1,18 +1,23 @@ +use std::rc::Rc; + 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}; +use tracing::event; -use crate::constants::{MapTile, BOARD, BOARD_HEIGHT, BOARD_WIDTH}; +use crate::constants::{MapTile, BOARD_HEIGHT, BOARD_WIDTH, RAW_BOARD}; use crate::direction::Direction; use crate::entity::Entity; +use crate::map::Map; use crate::pacman::Pacman; pub struct Game<'a> { canvas: &'a mut Canvas, map_texture: Texture<'a>, pacman: Pacman<'a>, + map: Rc, debug: bool, } @@ -21,15 +26,17 @@ impl Game<'_> { canvas: &'a mut Canvas, texture_creator: &'a TextureCreator, ) -> Game<'a> { + let map = Rc::new(Map::new(RAW_BOARD)); let pacman_atlas = texture_creator .load_texture("assets/32/pacman.png") .expect("Could not load pacman texture"); - let pacman = Pacman::new(Some(Game::cell_to_pixel((1, 4))), pacman_atlas); + let pacman = Pacman::new((1, 1), pacman_atlas, Rc::clone(&map)); Game { canvas, pacman: pacman, debug: false, + map: map, map_texture: texture_creator .load_texture("assets/map.png") .expect("Could not load pacman texture"), @@ -81,7 +88,7 @@ impl Game<'_> { if self.debug { for x in 0..BOARD_WIDTH { for y in 0..BOARD_HEIGHT { - let tile = BOARD[x as usize][y as usize]; + let tile = self.map.get_tile((x as i32, y as i32)).unwrap_or(MapTile::Empty); let mut color = None; if (x, y) == self.pacman.cell_position() { @@ -111,11 +118,12 @@ impl Game<'_> { } fn draw_cell(&mut self, cell: (u32, u32), color: Color) { + let position = Map::cell_to_pixel(cell); self.canvas.set_draw_color(color); self.canvas .draw_rect(sdl2::rect::Rect::new( - cell.0 as i32 * 24, - cell.1 as i32 * 24, + position.0 as i32, + position.1 as i32, 24, 24, )) diff --git a/src/map.rs b/src/map.rs new file mode 100644 index 0000000..374110f --- /dev/null +++ b/src/map.rs @@ -0,0 +1,61 @@ +use crate::constants::MapTile; +use crate::constants::{BOARD_HEIGHT, BOARD_WIDTH}; + +pub struct Map { + inner: [[MapTile; BOARD_HEIGHT as usize]; BOARD_WIDTH as usize] +} + +impl Map { + pub fn new(raw_board: [&str; BOARD_HEIGHT as usize]) -> Map { + let mut inner = [[MapTile::Empty; BOARD_HEIGHT as usize]; BOARD_WIDTH as usize]; + + for y in 0..BOARD_HEIGHT as usize { + let line = raw_board[y]; + + for x in 0..BOARD_WIDTH as usize { + if x >= line.len() { + break; + } + + let i = (y * (BOARD_WIDTH as usize) + x) as usize; + let character = line + .chars() + .nth(x as usize) + .unwrap_or_else(|| panic!("Could not get character at {} = ({}, {})", i, x, y)); + + let tile = match character { + '#' => MapTile::Wall, + '.' => MapTile::Pellet, + 'o' => MapTile::PowerPellet, + ' ' => MapTile::Empty, + c @ '0' | c @ '1' | c @ '2' | c @ '3' | c @ '4' => { + MapTile::StartingPosition(c.to_digit(10).unwrap() as u8) + }, + '=' => MapTile::Empty, + _ => panic!("Unknown character in board: {}", character), + }; + + inner[x as usize][y as usize] = tile; + } + } + + Map { + inner: inner + } + } + + pub fn get_tile(&self, cell: (i32, i32)) -> Option { + let x = cell.0 as usize; + let y = cell.1 as usize; + + if x >= BOARD_WIDTH as usize || y >= BOARD_HEIGHT as usize { + return None; + } + + Some(self.inner[x][y]) + } + + pub fn cell_to_pixel(cell: (u32, u32)) -> (i32, i32) { + ((cell.0 as i32) * 24, ((cell.1 + 3) as i32) * 24) + } +} \ No newline at end of file diff --git a/src/pacman.rs b/src/pacman.rs index d9fcb42..1d38bf0 100644 --- a/src/pacman.rs +++ b/src/pacman.rs @@ -1,12 +1,19 @@ +use std::rc::Rc; + use sdl2::{ render::{Canvas, Texture}, video::Window, }; +use tracing::event; use crate::{ - constants::{BOARD, MapTile}, - animation::AnimatedTexture, constants::CELL_SIZE, direction::Direction, entity::Entity, - modulation::SpeedModulator, + animation::AnimatedTexture, + constants::MapTile, + constants::{CELL_SIZE, BOARD_OFFSET}, + direction::Direction, + entity::Entity, + map::Map, + modulation::{SimpleTickModulator, TickModulator}, }; pub struct Pacman<'a> { @@ -15,20 +22,22 @@ pub struct Pacman<'a> { pub direction: Direction, pub next_direction: Option, pub stopped: bool, + map: Rc, speed: u32, - modulation: SpeedModulator, + modulation: SimpleTickModulator, sprite: AnimatedTexture<'a>, } impl Pacman<'_> { - pub fn new<'a>(starting_position: Option<(i32, i32)>, atlas: Texture<'a>) -> Pacman<'a> { + pub fn new<'a>(starting_position: (u32, u32), atlas: Texture<'a>, map: Rc) -> Pacman<'a> { Pacman { - position: starting_position.unwrap_or((0i32, 0i32)), + position: Map::cell_to_pixel(starting_position), direction: Direction::Right, next_direction: None, speed: 2, + map, stopped: false, - modulation: SpeedModulator::new(0.9333), + modulation: SimpleTickModulator::new(0.9333), sprite: AnimatedTexture::new(atlas, 4, 3, 32, 32, Some((-4, -4))), } } @@ -41,9 +50,10 @@ impl Pacman<'_> { } else { self.sprite.render(canvas, self.position, self.direction); } + } - fn next_cell(&self) -> (i32, i32) { - let (x, y) = self.direction.offset(); + pub fn next_cell(&self, direction: Option) -> (i32, i32) { + let (x, y) = direction.unwrap_or(self.direction).offset(); let cell = self.cell_position(); (cell.0 as i32 + x, cell.1 as i32 + y) } @@ -61,8 +71,8 @@ impl Entity for Pacman<'_> { } fn cell_position(&self) -> (u32, u32) { - let (x, y) = self.position(); - (x as u32 / CELL_SIZE, y as u32 / CELL_SIZE) + let (x, y) = self.position; + ((x as u32 / CELL_SIZE) - BOARD_OFFSET.0, (y as u32 / CELL_SIZE) - BOARD_OFFSET.1) } fn internal_position(&self) -> (u32, u32) { @@ -77,6 +87,17 @@ impl Entity for Pacman<'_> { self.direction = direction; self.next_direction = None; } + + let next = self.next_cell(None); + let next_tile = self.map.get_tile(next).unwrap_or(MapTile::Empty); + + if !self.stopped && next_tile == MapTile::Wall { + event!(tracing::Level::DEBUG, "Wall collision. Stopping."); + self.stopped = true; + } else if self.stopped && next_tile != MapTile::Wall { + event!(tracing::Level::DEBUG, "Wall collision resolved. Moving."); + self.stopped = false; + } } if !self.stopped && self.modulation.next() { @@ -96,10 +117,5 @@ impl Entity for Pacman<'_> { } } } - - let next = self.next_cell(); - if BOARD[next.1 as usize][next.0 as usize] == MapTile::Wall { - self.stopped = true; - } } }