Commit c3e0f6e7 authored by Mathieu Nivoliez's avatar Mathieu Nivoliez

Add lecture "Monster". Now, there are monsters in the generated map and they...

Add lecture "Monster". Now, there are monsters in the generated map and they shoot to player upon seeing him. In addition, each monster got a name, the player as well.
parent ddc2c218
Pipeline #779 passed with stage
in 7 minutes and 1 second
......@@ -10,3 +10,4 @@ Little Rogue Like made in Rust using the [guide](http://bfnightly.bracketproduct
- [Walking a Map](http://bfnightly.bracketproductions.com/rustbook/chapter_3.html)
- [A more interesting map](http://bfnightly.bracketproductions.com/rustbook/chapter_4.html)
- [Field of view](http://bfnightly.bracketproductions.com/rustbook/chapter_5.html)
- [Monster](http://bfnightly.bracketproductions.com/rustbook/chapter_6.html)
use rltk::RGB;
use specs::prelude::*;
use rltk::{RGB};
#[derive(Component)]
pub struct Position {
......@@ -17,9 +17,17 @@ pub struct Renderable {
#[derive(Component, Debug)]
pub struct Player {}
#[derive(Component, Debug)]
pub struct Monster {}
#[derive(Component, Debug)]
pub struct Name {
pub name: String,
}
#[derive(Component)]
pub struct Viewshed {
pub visible_tiles: Vec<rltk::Point>,
pub range: i32,
pub dirty: bool
}
\ No newline at end of file
pub dirty: bool,
}
// Only useful if compile to wasm
rltk::add_wasm_support!();
use rltk::{Console, GameState, Rltk, RGB};
use rltk::{Console, GameState, Point, Rltk, RGB};
use specs::prelude::*;
#[macro_use]
extern crate specs_derive;
......@@ -16,16 +16,27 @@ mod rect;
pub use rect::Rect;
mod visibility_system;
use visibility_system::VisibilitySystem;
mod monster_ai_system;
use monster_ai_system::MonsterAI;
#[derive(PartialEq, Copy, Clone)]
pub enum RunState {
Paused,
Running,
}
// Main State
pub struct State {
pub ecs: World,
pub runstate: RunState,
}
impl State {
fn run_systems(&mut self) {
let mut vis = VisibilitySystem {};
vis.run_now(&self.ecs);
let mut mob = MonsterAI {};
mob.run_now(&self.ecs);
self.ecs.maintain();
}
}
......@@ -34,16 +45,27 @@ impl GameState for State {
fn tick(&mut self, ctx: &mut Rltk) {
ctx.cls();
self.run_systems();
player_input(self, ctx);
match self.runstate {
RunState::Running => {
self.run_systems();
self.runstate = RunState::Paused;
}
RunState::Paused => {
self.runstate = player_input(self, ctx);
}
}
map::draw_map(&self.ecs, ctx);
let positions = self.ecs.read_storage::<Position>();
let renderables = self.ecs.read_storage::<Renderable>();
map::draw_map(&self.ecs, ctx);
let map = self.ecs.fetch::<Map>();
for (pos, render) in (&positions, &renderables).join() {
ctx.set(pos.x, pos.y, render.fg, render.bg, render.glyph);
let idx = map.xy_idx(pos.x, pos.y);
if map.visible_tiles[idx] {
ctx.set(pos.x, pos.y, render.fg, render.bg, render.glyph);
}
}
}
}
......@@ -54,17 +76,61 @@ fn main() {
let context = Rltk::init_simple8x8(80, 50, "Hello Rust World", "resources");
// Init global state with an ecs world
let mut gs = State { ecs: World::new() };
let mut gs = State {
ecs: World::new(),
runstate: RunState::Running,
};
// Register components to the world
gs.ecs.register::<Position>();
gs.ecs.register::<Renderable>();
gs.ecs.register::<Player>();
gs.ecs.register::<Monster>();
gs.ecs.register::<Name>();
gs.ecs.register::<Viewshed>();
let map = Map::new_map_rooms_and_corridors();
let (player_x, player_y) = map.rooms[0].center();
let mut rng = rltk::RandomNumberGenerator::new();
for (i, room) in map.rooms.iter().skip(1).enumerate() {
let (x, y) = room.center();
let glyph: u8;
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
.create_entity()
.with(Position { x, y })
.with(Renderable {
glyph: glyph,
fg: RGB::named(rltk::RED),
bg: RGB::named(rltk::BLACK),
})
.with(Viewshed {
visible_tiles: Vec::new(),
range: 8,
dirty: true,
})
.with(Monster {})
.with(Name {
name: format!("{} #{}", &name, i),
})
.build();
}
gs.ecs.insert(map);
gs.ecs.insert(Point::new(player_x, player_y));
// Create an entity
gs.ecs
......@@ -82,7 +148,10 @@ fn main() {
.with(Viewshed {
visible_tiles: Vec::new(),
range: 8,
dirty: true
dirty: true,
})
.with(Name {
name: "Player".to_string(),
})
.build();
......
extern crate specs;
use super::{Monster, Name, Viewshed};
use specs::prelude::*;
extern crate rltk;
use rltk::{console, Point};
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));
}
}
}
}
use super::{Map, Player, Position, State, TileType, Viewshed};
use rltk::{Rltk, VirtualKeyCode};
use super::{Map, Player, Position, RunState, State, TileType, Viewshed};
use rltk::{Rltk, VirtualKeyCode, Point};
use specs::prelude::*;
use std::cmp::{max, min};
......@@ -7,6 +7,7 @@ pub fn try_move_player(delta_x: i32, delta_y: i32, ecs: &mut World) {
let mut positions = ecs.write_storage::<Position>();
let mut players = ecs.write_storage::<Player>();
let mut viewsheds = ecs.write_storage::<Viewshed>();
let mut ppos = ecs.write_resource::<Point>();
let map = ecs.fetch::<Map>();
for (_player, pos, viewshed) in (&mut players, &mut positions, &mut viewsheds).join() {
......@@ -16,14 +17,17 @@ pub fn try_move_player(delta_x: i32, delta_y: i32, ecs: &mut World) {
pos.y = min(49, max(0, pos.y + delta_y));
viewshed.dirty = true;
ppos.x = pos.x;
ppos.y = pos.y;
}
}
}
pub fn player_input(gs: &mut State, ctx: &mut Rltk) {
pub fn player_input(gs: &mut State, ctx: &mut Rltk) -> RunState {
// Player movement
match ctx.key {
None => {} // Nothing happened
None => return RunState::Paused,
Some(key) => match key {
VirtualKeyCode::Left => try_move_player(-1, 0, &mut gs.ecs),
VirtualKeyCode::Numpad4 => try_move_player(-1, 0, &mut gs.ecs),
......@@ -37,7 +41,8 @@ pub fn player_input(gs: &mut State, ctx: &mut Rltk) {
VirtualKeyCode::Down => try_move_player(0, 1, &mut gs.ecs),
VirtualKeyCode::Numpad2 => try_move_player(0, 1, &mut gs.ecs),
VirtualKeyCode::J => try_move_player(0, 1, &mut gs.ecs),
_ => {}
_ => return RunState::Paused,
},
}
RunState::Running
}
......@@ -16,7 +16,7 @@ impl Rect {
}
pub fn intersect(&self, other: &Rect) -> bool {
self.x1 <= other.x1 && self.x2 >= other.x2 && self.y1 <= other.y1 && self.y2 >= other.y2
self.x1 <= other.x2 && self.x2 >= other.x1 && self.y1 <= other.y2 && self.y2 >= other.y1
}
pub fn center(&self) -> (i32, i32) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment