Browse Source

Preliminary entity support

master
Graham Northup 3 years ago
parent
commit
7de7e84649
Signed by untrusted user: grissess GPG Key ID: 5D000E6F539376FB
  1. 121
      src/world/entity/mod.rs
  2. 93
      src/world/mod.rs

121
src/world/entity/mod.rs

@ -0,0 +1,121 @@
use super::*;
use rogue_util::{coord::*, raster, grid::{Grid, region::Region}};
use std::collections::HashMap;
use std::fmt::Debug;
pub trait Visible {
fn is_transparent(&self) -> bool;
}
impl Visible for Tile {
fn is_transparent(&self) -> bool { self.content == Content::Air }
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum LinfDir {
UL, U, UR,
L, R,
DL, D, DR,
}
impl LinfDir {
pub fn to_v2i(self) -> V2i {
use LinfDir::*;
match self {
UL => V2i(-1, -1),
U => V2i(0, -1),
UR => V2i(1, -1),
L => V2i(-1, 0),
R => V2i(1, 0),
DL => V2i(-1, 1),
D => V2i(0, 1),
DR => V2i(1, 1),
}
}
}
#[derive(Debug, Clone)]
pub enum Action {
Move(LinfDir),
Wait,
}
impl Default for Action {
fn default() -> Action { Action::Wait }
}
#[derive(Debug, Clone)]
pub struct Observation {
pub sight: SightObs
}
#[derive(Debug, Clone)]
pub struct SightObs {
pub tiles: Grid<Option<V2i>>, // NB: Relative coordinate; 0,0 is this
pub entities: Vec<usize>, // NB: Entity indices
}
impl SightObs {
pub fn new(world: &World, v: V2i, sr: usize) -> SightObs {
let srsq = (sr as Vi) * (sr as Vi);
SightObs {
tiles: Grid::from_generator(|p| {
if p.l2_sq() > srsq {
return None;
}
{
let mut rg = world.region_mut();
for pt in raster::line(v, v + p) {
let tile = rg.get_or_create(pt);
if !tile.is_transparent() {
return None;
}
}
}
Some(v + p)
}, V2i(-(sr as Vi), -(sr as Vi)), V2i(2*sr as Vi, 2*sr as Vi)).unwrap(),
entities: world.entities().enumerate().filter_map(|(idx, eref)| {
let e = eref.borrow();
let pos = e.pos();
if (pos - v).l2_sq() > srsq {
return None;
}
{
let mut rg = world.region_mut();
for pt in raster::line(v, pos) {
let tile = rg.get_or_create(pt);
if !tile.is_transparent() {
return None;
}
}
}
Some(idx)
}).collect(),
}
}
}
const DEFAULT_SIGHT_RADIUS: usize = 10;
const DEFAULT_ACT_TIME: usize = 10000;
const ECLS_LIVING: usize = 1;
pub trait Entity: Debug {
fn pos(&self) -> V2i;
fn set_pos(&mut self, v: V2i);
fn class(&self) -> usize { 0 }
fn hp(&self) -> isize { 100 }
fn set_hp(&mut self, hp: isize) {}
fn char(&self) -> char { 'E' }
fn sight(&self) -> usize { DEFAULT_SIGHT_RADIUS }
fn act_time(&self) -> usize { DEFAULT_ACT_TIME }
fn is_dead(&self) -> bool { self.hp() <= 0 }
fn act(&mut self, obs: &Observation) -> Action { Action::Wait }
}

93
src/world/mod.rs

@ -1,7 +1,12 @@
pub mod render;
pub mod gen;
pub mod entity;
use rogue_util::{coord::*, grid::{Grid, region::{Region, RegionConfig}}};
use std::cell::RefCell;
use std::io::{self, Write};
use std::ops::{Deref, DerefMut};
use entity::Entity;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Content {
@ -32,7 +37,8 @@ impl Default for Tile {
pub struct World {
seed: u64,
cur_region: usize,
regions: Vec<Region<Tile>>,
regions: Vec<RefCell<Region<Tile>>>,
entities: Vec<RefCell<Box<dyn Entity>>>, // NB: Player is ent 0
}
impl World {
@ -48,16 +54,55 @@ impl World {
World {
seed,
cur_region: 0,
regions: vec![start_region],
regions: vec![RefCell::new(start_region)],
entities: Vec::new(),
}
}
pub fn region(&self) -> &Region<Tile> {
&self.regions[self.cur_region]
pub fn region<'s>(&'s self) -> impl Deref<Target=Region<Tile>> + 's {
self.regions[self.cur_region].borrow()
}
pub fn region_mut(&mut self) -> &mut Region<Tile> {
&mut self.regions[self.cur_region]
pub fn region_mut<'s>(&'s self) -> impl DerefMut<Target=Region<Tile>> + 's {
self.regions[self.cur_region].borrow_mut()
}
pub fn player<'s>(&'s self) -> impl Deref<Target=Box<dyn Entity>> + 's {
self.entities[0].borrow()
}
pub fn player_mut<'s>(&'s mut self) -> impl DerefMut<Target=Box<dyn Entity>> + 's {
self.entities[0].borrow_mut()
}
pub fn entities(&self) -> impl Iterator<Item=&RefCell<Box<dyn Entity>>> {
self.entities.iter()
}
pub fn entity<'s>(&'s self, idx: usize) -> impl Deref<Target=Box<dyn Entity>> + 's{
self.entities[idx].borrow()
}
pub fn entity_mut<'s>(&'s mut self, idx: usize) -> impl DerefMut<Target=Box<dyn Entity>> + 's {
self.entities[idx].borrow_mut()
}
pub fn add_entity(&mut self, ent: Box<dyn Entity>) {
self.entities.push(RefCell::new(ent));
}
pub fn render<W: Write>(&self, rs: &render::RenderState, mut out: &mut W) -> io::Result<()> {
rs.render(&self.region(), &mut render::InvertRenderer, &mut out)?;
let sr = rs.screen_rect();
for eref in self.entities() {
let e = eref.borrow();
let pos = e.pos();
if sr.contains(pos) {
rs.go_to_pt(pos, out)?;
write!(out, "{}", e.char())?;
}
}
Ok(())
}
}
@ -66,11 +111,11 @@ mod test {
use super::*;
#[test]
fn room_align() -> std::io::Result<()> {
fn room_align() -> io::Result<()> {
let mut w = World::new(0);
{
let r = w.region_mut();
let mut r = w.region_mut();
let gs = r.grid_size();
r.get_or_create(V2i(0, 0));
r.get_or_create(V2i(0, gs.1));
@ -85,8 +130,34 @@ mod test {
let rs = render::RenderState::new(V2i(width as isize, height as isize));
let mut out = std::io::stdout();
rs.render(w.region(), &mut render::InvertRenderer, &mut out)?;
rs.draw_unpop(w.region(), &mut out)?;
rs.draw_grid(w.region(), &mut out)
let r = w.region();
rs.render(&r, &mut render::InvertRenderer, &mut out)?;
rs.draw_unpop(&r, &mut out)?;
rs.draw_grid(&r, &mut out)
}
#[test]
fn world_with_entity() -> io::Result<()> {
let mut w = World::new(0);
{
let mut r = w.region_mut();
r.get_or_create(V2i(0, 0));
}
let (width, height) = termion::terminal_size()?;
let rs = render::RenderState::new(V2i(width as isize, height as isize));
let mut out = std::io::stdout();
#[derive(Debug)]
struct Ent;
impl Entity for Ent {
fn pos(&self) -> V2i { V2i(0, 0) }
fn set_pos(&mut self, v: V2i) {}
}
w.add_entity(Box::new(Ent));
w.render(&rs, &mut out)
}
}
Loading…
Cancel
Save