Complete Chapter 2.5

This commit is contained in:
Timothy Warren 2021-10-26 15:43:59 -04:00
parent b8be87868e
commit 30b0449e99
4 changed files with 95 additions and 11 deletions

View File

@ -24,3 +24,11 @@ pub struct Viewshed {
pub range: i32, pub range: i32,
pub dirty: bool, pub dirty: bool,
} }
#[derive(Component)]
pub struct Monster {}
#[derive(Component)]
pub struct Name {
pub name: String,
}

View File

@ -1,4 +1,4 @@
use rltk::{GameState, Rltk, RGB}; use rltk::{GameState, Point, Rltk, RGB};
use specs::prelude::*; use specs::prelude::*;
mod components; mod components;
@ -10,11 +10,20 @@ use player::*;
mod rect; mod rect;
mod visibility_system; mod visibility_system;
use visibility_system::VisibilitySystem; use visibility_system::VisibilitySystem;
mod monster_ai_system;
use monster_ai_system::*;
pub use rect::Rect; pub use rect::Rect;
#[derive(PartialEq, Copy, Clone)]
pub enum RunState {
Paused,
Running,
}
pub struct State { pub struct State {
ecs: World, pub ecs: World,
pub runstate: RunState,
} }
impl State { impl State {
@ -22,6 +31,9 @@ impl State {
let mut vis = VisibilitySystem {}; let mut vis = VisibilitySystem {};
vis.run_now(&self.ecs); vis.run_now(&self.ecs);
let mut mob = MonsterAI {};
mob.run_now(&self.ecs);
self.ecs.maintain(); self.ecs.maintain();
} }
} }
@ -30,8 +42,12 @@ impl GameState for State {
fn tick(&mut self, ctx: &mut Rltk) { fn tick(&mut self, ctx: &mut Rltk) {
ctx.cls(); ctx.cls();
player_input(self, ctx); if self.runstate == RunState::Running {
self.run_systems(); self.run_systems();
self.runstate = RunState::Paused;
} else {
self.runstate = player_input(self, ctx);
}
draw_map(&self.ecs, ctx); draw_map(&self.ecs, ctx);
@ -55,23 +71,44 @@ fn main() -> rltk::BError {
.with_title("Roguelike Tutorial") .with_title("Roguelike Tutorial")
.build()?; .build()?;
let mut gs = State { ecs: World::new() }; let mut gs = State {
ecs: World::new(),
runstate: RunState::Running,
};
gs.ecs.register::<Position>(); gs.ecs.register::<Position>();
gs.ecs.register::<Renderable>(); gs.ecs.register::<Renderable>();
gs.ecs.register::<Player>(); gs.ecs.register::<Player>();
gs.ecs.register::<Viewshed>(); gs.ecs.register::<Viewshed>();
gs.ecs.register::<Monster>();
gs.ecs.register::<Name>();
let map: Map = Map::new_map_rooms_and_corridors(); let map: Map = Map::new_map_rooms_and_corridors();
let (player_x, player_y) = map.rooms[0].center(); let (player_x, player_y) = map.rooms[0].center();
for room in map.rooms.iter().skip(1) { let mut rng = rltk::RandomNumberGenerator::new();
for (i, room) in map.rooms.iter().skip(1).enumerate() {
let (x, y) = room.center(); let (x, y) = room.center();
let glyph: rltk::FontCharType;
let name: String;
let roll = rng.roll_dice(1, 2);
match roll {
1 => {
glyph = rltk::to_cp437('g');
name = "Goblin".to_string();
}
_ => {
glyph = rltk::to_cp437('o');
name = "Orc".to_string();
}
}
gs.ecs gs.ecs
.create_entity() .create_entity()
.with(Position { x, y }) .with(Position { x, y })
.with(Renderable { .with(Renderable {
glyph: rltk::to_cp437('g'), glyph,
fg: RGB::named(rltk::RED), fg: RGB::named(rltk::RED),
bg: RGB::named(rltk::BLACK), bg: RGB::named(rltk::BLACK),
}) })
@ -80,6 +117,10 @@ fn main() -> rltk::BError {
range: 8, range: 8,
dirty: true, dirty: true,
}) })
.with(Monster {})
.with(Name {
name: format!("{} #{}", &name, i),
})
.build(); .build();
} }
@ -100,9 +141,13 @@ fn main() -> rltk::BError {
range: 8, range: 8,
dirty: true, dirty: true,
}) })
.with(Name {
name: "Player".to_string(),
})
.build(); .build();
gs.ecs.insert(map); gs.ecs.insert(map);
gs.ecs.insert(Point::new(player_x, player_y));
rltk::main_loop(context, gs) rltk::main_loop(context, gs)
} }

24
src/monster_ai_system.rs Normal file
View File

@ -0,0 +1,24 @@
use super::{Monster, Name, Viewshed};
use rltk::{console, Point};
use specs::prelude::*;
pub struct MonsterAI {}
impl<'a> System<'a> for MonsterAI {
type SystemData = (
ReadExpect<'a, Point>,
ReadStorage<'a, Viewshed>,
ReadStorage<'a, Monster>,
ReadStorage<'a, Name>,
);
fn run(&mut self, data: Self::SystemData) {
let (player_pos, viewshed, monster, name) = data;
for (viewshed, _monster, name) in (&viewshed, &monster, &name).join() {
if viewshed.visible_tiles.contains(&*player_pos) {
console::log(format!("{} shouts insults", name.name));
}
}
}
}

View File

@ -1,5 +1,6 @@
use super::{Map, Player, Position, State, TileType, Viewshed}; use super::{Map, Player, Position, State, TileType, Viewshed};
use rltk::{Rltk, VirtualKeyCode}; use crate::RunState;
use rltk::{Point, Rltk, VirtualKeyCode};
use specs::prelude::*; use specs::prelude::*;
use std::cmp::{max, min}; use std::cmp::{max, min};
@ -15,15 +16,19 @@ pub fn try_move_player(delta_x: i32, delta_y: i32, ecs: &mut World) {
pos.x = min(79, max(0, pos.x + delta_x)); pos.x = min(79, max(0, pos.x + delta_x));
pos.y = min(49, max(0, pos.y + delta_y)); pos.y = min(49, max(0, pos.y + delta_y));
let mut ppos = ecs.write_resource::<Point>();
ppos.x = pos.x;
ppos.y = pos.y;
viewshed.dirty = true; viewshed.dirty = true;
} }
} }
} }
pub fn player_input(gs: &mut State, ctx: &mut Rltk) { pub fn player_input(gs: &mut State, ctx: &mut Rltk) -> RunState {
// Player movement // Player movement
match ctx.key { match ctx.key {
None => {} // Nothing happened None => return RunState::Paused, // Nothing happened
Some(key) => match key { Some(key) => match key {
VirtualKeyCode::Left | VirtualKeyCode::Numpad4 | VirtualKeyCode::H => { VirtualKeyCode::Left | VirtualKeyCode::Numpad4 | VirtualKeyCode::H => {
try_move_player(-1, 0, &mut gs.ecs) try_move_player(-1, 0, &mut gs.ecs)
@ -41,7 +46,9 @@ pub fn player_input(gs: &mut State, ctx: &mut Rltk) {
try_move_player(0, 1, &mut gs.ecs) try_move_player(0, 1, &mut gs.ecs)
} }
_ => {} _ => return RunState::Paused,
}, },
} }
RunState::Running
} }