This commit is contained in:
Paul Brinkmeier 2025-11-30 02:38:35 +01:00
parent c7194cf2bc
commit 966582e0c2
2 changed files with 100 additions and 72 deletions

View File

@ -17,7 +17,8 @@ pub struct GameModel {
pub enum GameEvent { pub enum GameEvent {
Quit, Quit,
Nop, Nop,
MovePlayer(V2<isize>), PlayerMove(V2<isize>),
PlayerDash(V2<isize>),
} }
impl GameEvent { impl GameEvent {
@ -26,14 +27,14 @@ impl GameEvent {
use KeyCode::Char; use KeyCode::Char;
match key_event.code { match key_event.code {
Char('q') => return GameEvent::Quit, Char('q') => return GameEvent::Quit,
Char('j') => return GameEvent::MovePlayer(V2::new(0, 1)), Char('j') => return GameEvent::PlayerMove(V2::new(0, 1)),
Char('k') => return GameEvent::MovePlayer(V2::new(0, -1)), Char('k') => return GameEvent::PlayerMove(V2::new(0, -1)),
Char('h') => return GameEvent::MovePlayer(V2::new(-1, 0)), Char('h') => return GameEvent::PlayerMove(V2::new(-1, 0)),
Char('l') => return GameEvent::MovePlayer(V2::new(1, 0)), Char('l') => return GameEvent::PlayerMove(V2::new(1, 0)),
Char('J') => return GameEvent::MovePlayer(V2::new(0, 2)), Char('J') => return GameEvent::PlayerDash(V2::new(0, 1)),
Char('K') => return GameEvent::MovePlayer(V2::new(0, -2)), Char('K') => return GameEvent::PlayerDash(V2::new(0, -1)),
Char('H') => return GameEvent::MovePlayer(V2::new(-2, 0)), Char('H') => return GameEvent::PlayerDash(V2::new(-1, 0)),
Char('L') => return GameEvent::MovePlayer(V2::new(2, 0)), Char('L') => return GameEvent::PlayerDash(V2::new(1, 0)),
_ => (), _ => (),
} }
} }
@ -43,21 +44,53 @@ impl GameEvent {
} }
struct Room { struct Room {
size: V2<usize>, tiles: Grid<Tile>,
}
impl Room {
fn in_bounds(&self, player_pos: P2<isize>) -> bool {
(0..self.size.x as isize).contains(&player_pos.x)
&& (0..self.size.y as isize).contains(&player_pos.y)
}
} }
impl Room {}
impl GameModel { impl GameModel {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
player_pos: P2::new(1, 1), player_pos: P2::new(1, 1),
room: Room { room: Room {
size: V2::new(20, 10), tiles: {
let w = 30;
let h = 12;
let mut tiles = Grid::from_fn(w, h, |x, y| {
let is_vertical_boundary = [0, w - 1].contains(&x);
let is_horizontal_boundary = [0, h - 1].contains(&y);
if is_vertical_boundary || is_horizontal_boundary {
Tile::Wall
} else {
Tile::Floor
}
});
tiles
.get_mut(P2::new(1, 1))
.map(|tile| *tile = Tile::Ladder);
tiles
.get_mut(P2::new(5, 2))
.map(|tile| *tile = Tile::Amphora);
tiles.get_mut(P2::new(8, 5)).map(|tile| *tile = Tile::Frog);
tiles.get_mut(P2::new(7, 6)).map(|tile| *tile = Tile::Water);
tiles.get_mut(P2::new(8, 6)).map(|tile| *tile = Tile::Water);
tiles.get_mut(P2::new(9, 6)).map(|tile| *tile = Tile::Water);
tiles.get_mut(P2::new(8, 7)).map(|tile| *tile = Tile::Wall);
tiles.get_mut(P2::new(9, 7)).map(|tile| *tile = Tile::Wall);
tiles.get_mut(P2::new(10, 2)).map(|tile| *tile = Tile::Portal);
tiles.get_mut(P2::new(18, 2)).map(|tile| *tile = Tile::Portal);
tiles.get_mut(P2::new(10, 8)).map(|tile| *tile = Tile::Portal);
tiles.get_mut(P2::new(18, 8)).map(|tile| *tile = Tile::Portal);
tiles
},
}, },
} }
} }
@ -66,14 +99,32 @@ impl GameModel {
match GameEvent::from_crossterm(event) { match GameEvent::from_crossterm(event) {
GameEvent::Quit => None, GameEvent::Quit => None,
GameEvent::Nop => Some(self), GameEvent::Nop => Some(self),
GameEvent::MovePlayer(direction) => { GameEvent::PlayerMove(direction) => {
let player_pos = self.player_pos + direction; let player_pos = self.player_pos + direction;
if self.room.in_bounds(player_pos) { if let Some(target_tile) = self.room.tiles.get(player_pos)
&& target_tile.may_enter()
{
Some(Self { player_pos, ..self }) Some(Self { player_pos, ..self })
} else { } else {
Some(self) Some(self)
} }
} }
GameEvent::PlayerDash(direction) => {
let max_dash_tiles = 10;
let mut player_pos = self.player_pos;
for _ in 0..max_dash_tiles {
let next_pos = player_pos + direction;
if let Some(target_tile) = self.room.tiles.get(next_pos) && target_tile.may_enter() {
player_pos = next_pos;
if target_tile.may_interact() {
break
}
} else {
break;
}
}
Some(Self { player_pos, ..self })
}
} }
} }
@ -87,43 +138,7 @@ impl GameModel {
} }
fn render_tiles(&self) -> Grid<Tile> { fn render_tiles(&self) -> Grid<Tile> {
let w = self.room.size.x; let mut tiles = self.room.tiles.clone();
let h = self.room.size.y;
let mut tiles = Grid::from_fn(w, h, |x, y| {
let is_vertical_boundary = [0, w - 1].contains(&x);
let is_horizontal_boundary = [0, h - 1].contains(&y);
let is_corner = is_vertical_boundary && is_horizontal_boundary;
if is_corner {
Tile::Corner
} else if is_vertical_boundary {
Tile::VerticalWall
} else if is_horizontal_boundary {
Tile::HorizontalWall
} else {
Tile::Floor
}
});
tiles
.get_mut(P2::new(1, 1))
.map(|tile| *tile = Tile::Ladder);
tiles
.get_mut(P2::new(5, 2))
.map(|tile| *tile = Tile::Amphora);
tiles.get_mut(P2::new(8, 5)).map(|tile| *tile = Tile::Frog);
tiles.get_mut(P2::new(7, 6)).map(|tile| *tile = Tile::Water);
tiles.get_mut(P2::new(8, 6)).map(|tile| *tile = Tile::Water);
tiles.get_mut(P2::new(9, 6)).map(|tile| *tile = Tile::Water);
tiles.get_mut(P2::new(8, 7)).map(|tile| *tile = Tile::Water);
tiles.get_mut(P2::new(9, 7)).map(|tile| *tile = Tile::Water);
tiles tiles
.get_mut(self.player_pos) .get_mut(self.player_pos)
@ -133,6 +148,7 @@ impl GameModel {
} }
} }
#[derive(Clone)]
enum Tile { enum Tile {
Floor, Floor,
Ladder, Ladder,
@ -140,17 +156,14 @@ enum Tile {
Amphora, Amphora,
Frog, Frog,
Water, Water,
Corner, Wall,
VerticalWall, Portal,
HorizontalWall,
} }
impl Tile { impl Tile {
fn render(&self, cell: &mut Cell) { fn render(&self, cell: &mut Cell) {
match self { match self {
Tile::Floor => { Tile::Floor => {}
cell.set_symbol(" ");
}
Tile::Ladder => { Tile::Ladder => {
cell.set_symbol("Ħ"); cell.set_symbol("Ħ");
} }
@ -169,15 +182,29 @@ impl Tile {
.set_bg(Color::Blue) .set_bg(Color::Blue)
.set_fg(Color::White); .set_fg(Color::White);
} }
Tile::Corner => { Tile::Wall => {
cell.set_symbol(""); cell.set_bg(Color::DarkGray);
} }
Tile::VerticalWall => { Tile::Portal => {
cell.set_symbol(""); cell.set_symbol("@").set_fg(Color::LightBlue);
}, }
Tile::HorizontalWall => { }
cell.set_symbol(""); }
},
fn may_enter(&self) -> bool {
match self {
Tile::Wall => false,
_ => true,
}
}
fn may_interact(&self) -> bool {
match self {
Tile::Amphora => true,
Tile::Frog => true,
Tile::Ladder => true,
Tile::Portal => true,
_ => false,
} }
} }
} }

View File

@ -44,7 +44,7 @@ impl<T: Copy + Div<T>> Div<T> for P2<T> {
} }
} }
#[derive(Debug)] #[derive(Clone, Copy, Debug)]
pub struct V2<T> { pub struct V2<T> {
pub x: T, pub x: T,
pub y: T, pub y: T,
@ -64,6 +64,7 @@ impl<T: Copy + Div<T>> Div<T> for V2<T> {
} }
} }
#[derive(Clone)]
pub struct Grid<T> { pub struct Grid<T> {
pub dims: V2<usize>, pub dims: V2<usize>,
elements: Vec<T>, elements: Vec<T>,
@ -103,4 +104,4 @@ impl<T> Grid<T> {
None None
} }
} }
} }