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 {
Quit,
Nop,
MovePlayer(V2<isize>),
PlayerMove(V2<isize>),
PlayerDash(V2<isize>),
}
impl GameEvent {
@ -26,14 +27,14 @@ impl GameEvent {
use KeyCode::Char;
match key_event.code {
Char('q') => return GameEvent::Quit,
Char('j') => return GameEvent::MovePlayer(V2::new(0, 1)),
Char('k') => return GameEvent::MovePlayer(V2::new(0, -1)),
Char('h') => return GameEvent::MovePlayer(V2::new(-1, 0)),
Char('l') => return GameEvent::MovePlayer(V2::new(1, 0)),
Char('J') => return GameEvent::MovePlayer(V2::new(0, 2)),
Char('K') => return GameEvent::MovePlayer(V2::new(0, -2)),
Char('H') => return GameEvent::MovePlayer(V2::new(-2, 0)),
Char('L') => return GameEvent::MovePlayer(V2::new(2, 0)),
Char('j') => return GameEvent::PlayerMove(V2::new(0, 1)),
Char('k') => return GameEvent::PlayerMove(V2::new(0, -1)),
Char('h') => return GameEvent::PlayerMove(V2::new(-1, 0)),
Char('l') => return GameEvent::PlayerMove(V2::new(1, 0)),
Char('J') => return GameEvent::PlayerDash(V2::new(0, 1)),
Char('K') => return GameEvent::PlayerDash(V2::new(0, -1)),
Char('H') => return GameEvent::PlayerDash(V2::new(-1, 0)),
Char('L') => return GameEvent::PlayerDash(V2::new(1, 0)),
_ => (),
}
}
@ -43,21 +44,53 @@ impl GameEvent {
}
struct Room {
size: V2<usize>,
}
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)
}
tiles: Grid<Tile>,
}
impl Room {}
impl GameModel {
pub fn new() -> Self {
Self {
player_pos: P2::new(1, 1),
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) {
GameEvent::Quit => None,
GameEvent::Nop => Some(self),
GameEvent::MovePlayer(direction) => {
GameEvent::PlayerMove(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 })
} else {
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> {
let w = self.room.size.x;
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);
let mut tiles = self.room.tiles.clone();
tiles
.get_mut(self.player_pos)
@ -133,6 +148,7 @@ impl GameModel {
}
}
#[derive(Clone)]
enum Tile {
Floor,
Ladder,
@ -140,17 +156,14 @@ enum Tile {
Amphora,
Frog,
Water,
Corner,
VerticalWall,
HorizontalWall,
Wall,
Portal,
}
impl Tile {
fn render(&self, cell: &mut Cell) {
match self {
Tile::Floor => {
cell.set_symbol(" ");
}
Tile::Floor => {}
Tile::Ladder => {
cell.set_symbol("Ħ");
}
@ -169,15 +182,29 @@ impl Tile {
.set_bg(Color::Blue)
.set_fg(Color::White);
}
Tile::Corner => {
cell.set_symbol("");
Tile::Wall => {
cell.set_bg(Color::DarkGray);
}
Tile::VerticalWall => {
cell.set_symbol("");
},
Tile::HorizontalWall => {
cell.set_symbol("");
},
Tile::Portal => {
cell.set_symbol("@").set_fg(Color::LightBlue);
}
}
}
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 x: 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 dims: V2<usize>,
elements: Vec<T>,
@ -103,4 +104,4 @@ impl<T> Grid<T> {
None
}
}
}
}