Browse Source

Fixed some bugs and miscellaneous problems (like slow render speed)

master
Thomas Johnson 3 years ago
parent
commit
41b9f00f8d
  1. 13
      src/main.rs
  2. 80
      src/world/gen.rs
  3. 24
      src/world/mod.rs
  4. 98
      src/world/render.rs

13
src/main.rs

@ -38,6 +38,17 @@ fn main() -> io::Result<()>
loop {
w.render(&mut rs, &mut stdout);
stdout.flush();
w.step();
if let Some(()) = w.step() { break; }
}
eprintln!("{}{}",
termion::clear::All,
termion::cursor::Goto(1, 1),
);
std::mem::drop(stdout);
print!("Thank you for playi");
io::stdout().flush();
rand_distr::Poisson::new(-1.0).unwrap();
Ok(())
}

80
src/world/gen.rs

@ -11,7 +11,6 @@ use std::hash::{Hash, Hasher};
use std::collections::hash_map::DefaultHasher;
const GRID_SIZE: isize = 32;
const GRID_USIZE: usize = GRID_SIZE as usize;
const AVG_ROOMS_PER_CELL: f64 = 2.0;
@ -29,7 +28,7 @@ const PATH_STRATEGY_WEIGHTS: [usize; 4] = [2500, 5, 100, 100];
const USE_RECTANGLE_CENTER_FOR_PATH_END_PROB: f64 = 0.5;
const PATH_ORTHOG_AVG_NUM_STOPS_PER_LEN: f64 = 0.1;
const PATH_ORTHOG_AVG_NUM_STOPS_PER_LEN: f64 = 0.5;
const PATH_CIRC_AVG_NUM_STOPS_PER_LEN: f64 = 0.3;
@ -175,7 +174,7 @@ fn get_room_shapes(seed: u64, coords: V2i) -> Vec<RoomShape>
let rect_size_dist = Uniform::new_inclusive(RECT_MIN_SIZE, RECT_MAX_SIZE);
let circ_rad_dist = Uniform::new_inclusive(CIRC_MIN_RAD, CIRC_MAX_RAD);
for ii in 0 .. nrooms
for _ii in 0 .. nrooms
{
let shape = match chooser.sample(&mut rg)
{
@ -211,7 +210,7 @@ fn carve_rooms<T: Iterator<Item=RoomShape>>(map: &mut [Tile], shapes: T)
{
match shape
{
RoomShape::Rect(rect) =>
RoomShape::Rect(_) =>
{
for tile in bbox.iter()
{ map[(tile.1 * GRID_SIZE + tile.0) as usize].content = Content::Air; }
@ -279,10 +278,11 @@ fn get_path_endpoint<R: Rng>(rs: &RoomShape, rg: &mut R) -> V2i
}
}
fn carve_between(coords: V2i, rs1: &RoomShape, rs2: &RoomShape) -> Option<Path>
fn carve_between(seed: u64, coords: V2i, rs1: &RoomShape, rs2: &RoomShape) -> Option<Path>
{
if rs2 < rs1 { return carve_between(coords, rs2, rs1); }
if rs2 < rs1 { return carve_between(seed, coords, rs2, rs1); }
let mut hasher = DefaultHasher::new();
seed.hash(&mut hasher);
hash_unique_pair(coords, &rs1, &rs2, &mut hasher);
let mut rg = SmallRng::seed_from_u64(hasher.finish());
@ -308,27 +308,41 @@ fn carve_between(coords: V2i, rs1: &RoomShape, rs2: &RoomShape) -> Option<Path>
.unwrap().sample(&mut rg);
let mut tpoints = Vec::new();
tpoints.push(ep1);
for ii in 0 .. npoints
for _ii in 0 .. npoints
{
tpoints.push(gen_rand_in_rect(&brect, &mut rg));
}
tpoints.push(ep2);
tpoints.sort_by(|a, b| (*a - ep1).linf().cmp(&(*b - ep2).linf()));
let mut stops = Vec::new();
tpoints.sort_by(|a, b| (*a - ep1).linf().cmp(&(*b - ep1).linf()));
let dir = V2i((ep2.0 - ep1.0).signum(), (ep2.1 - ep1.1).signum());
let mut paths = Vec::new();
for ii in 0 .. npoints as usize + 1
{
let diff = tpoints[ii] - ep1;
if diff.0 > diff.1
let diffn = tpoints[ii + 1] - ep1;
let linf = (tpoints[ii + 1] - ep1).linf();
let stop1 = if diff.0.abs() > diff.1.abs()
{
stops.push(Path::Line(tpoints[ii], V2i(tpoints[ii].0, tpoints[ii + 1].1)));
stops.push(Path::Line(V2i(tpoints[ii].0, tpoints[ii + 1].1), tpoints[ii + 1]));
V2i(linf * dir.0 + ep1.0, tpoints[ii].1)
} else
{
stops.push(Path::Line(tpoints[ii], V2i(tpoints[ii + 1].0, tpoints[ii].1)));
stops.push(Path::Line(V2i(tpoints[ii + 1].0, tpoints[ii].1), tpoints[ii + 1]));
V2i(tpoints[ii].0, linf * dir.1 + ep1.1)
};
let do_stop2 = (diff.0.abs() > diff.1.abs()) ^ (diffn.0.abs() > diffn.1.abs());
if do_stop2
{
let stop2 = ep1 + V2i(linf, linf) * dir;
paths.push(Path::Line(tpoints[ii], stop1));
paths.push(Path::Line(stop1, stop2));
paths.push(Path::Line(stop2, tpoints[ii + 1]));
} else
{
paths.push(Path::Line(tpoints[ii], stop1));
paths.push(Path::Line(stop1, tpoints[ii + 1]));
}
}
Some(Path::Piecewise(stops))
Some(Path::Piecewise(paths))
}
3 =>
{
@ -341,7 +355,7 @@ fn carve_between(coords: V2i, rs1: &RoomShape, rs2: &RoomShape) -> Option<Path>
.unwrap().sample(&mut rg);
let mut tpoints = Vec::new();
tpoints.push(ep1);
for ii in 0 .. npoints
for _ii in 0 .. npoints
{
tpoints.push(bcirc.gen_rand_in(&mut rg));
}
@ -349,7 +363,7 @@ fn carve_between(coords: V2i, rs1: &RoomShape, rs2: &RoomShape) -> Option<Path>
fn s(a: V2i) -> isize { a.0 + a.1 }
fn dot(a: V2i, b: V2i) -> isize { s(a * b) }
let diff = ep2 - ep1;
tpoints.sort_by(|a, b| dot((*a - ep1), diff).cmp(&dot((*b - ep1), diff)));
tpoints.sort_by(|a, b| dot(*a - ep1, diff).cmp(&dot(*b - ep1, diff)));
let mut stops = Vec::new();
for ii in 0 .. npoints as usize + 1
{
@ -361,13 +375,13 @@ fn carve_between(coords: V2i, rs1: &RoomShape, rs2: &RoomShape) -> Option<Path>
}
}
fn maybe_carve_between(coords: V2i, rs1: &RoomShape, rs2: &RoomShape, radius: isize) -> Option<Path>
fn maybe_carve_between(seed: u64, coords: V2i, rs1: &RoomShape, rs2: &RoomShape, radius: isize) -> Option<Path>
{
let o1 = rs1.origin().div_euclid(V2i(GRID_SIZE, GRID_SIZE));
let o2 = rs2.origin().div_euclid(V2i(GRID_SIZE, GRID_SIZE));
if (o1 - o2).linf() <= radius
{
carve_between(coords, rs1, rs2)
carve_between(seed, coords, rs1, rs2)
} else
{
None
@ -388,7 +402,7 @@ fn carve_paths<T: Iterator<Item=Path>>(map: &mut [Tile], paths: T)
},
Line(p1, p2) =>
{
let mut lineiter = raster::line(p1, p2);
let lineiter = raster::line(p1, p2);
for tile in lineiter
{
if gbox.contains(tile)
@ -406,7 +420,7 @@ pub fn carve(seed: u64, grid: &mut Grid<Tile>, coords: V2i)
let rooms = get_nearby_room_shapes(seed, coords, 1).collect::<Vec<_>>();
carve_rooms(grid.array_mut(), rooms.iter().map(|c| c.clone()));
let cpi = rooms.iter().map(|a| rooms.iter().map(move |b| (a, b))).flatten().map(|(a, b)| (a, b));
let paths = cpi.map(|(a, b)| maybe_carve_between(coords, a, b, 1)).filter_map(|o| o);
let paths = cpi.map(|(a, b)| maybe_carve_between(seed, coords, a, b, 1)).filter_map(|o| o);
carve_paths(grid.array_mut(), paths);
}
@ -415,6 +429,8 @@ mod test
{
use super::*;
const GRID_USIZE: usize = GRID_SIZE as usize;
#[test]
fn list_rooms()
{
@ -458,5 +474,27 @@ mod test
assert!(r.contains(e));
}
}
#[test]
fn single_path_test()
{
for seed in 0u64..20u64
{
let origin = V2i(0, 0);
let mut map = vec![Tile { content: Content::Stone }; GRID_USIZE * GRID_USIZE];
let shape1 = RoomShape::Circ(V2i(0, 0), 0);
let shape2 = RoomShape::Circ(V2i(GRID_SIZE - 1, GRID_SIZE - 1), 0);
carve_paths(&mut map[..], carve_between(seed, origin, &shape1, &shape2).into_iter());
for x in 0 .. GRID_USIZE
{
for y in 0 .. GRID_USIZE
{
print!("{}", if let Tile{ content: Content::Air } = map[x * GRID_USIZE + y] { ' ' } else { '#' });
}
println!("");
}
println!("");
}
}
}

24
src/world/mod.rs

@ -122,7 +122,7 @@ impl World {
Ok(())
}
pub fn step(&mut self) {
pub fn step(&mut self) -> Option<()> {
let mut ents: Vec<_> = self.entities().enumerate().map(|(i, eref)| {
(i, eref.borrow().next_time())
}).collect();
@ -144,12 +144,12 @@ impl World {
{
let mut e = self.entity_mut(i);
let act = e.act(&obs);
self.perform_act(e, act);
self.perform_act(e, act)
}
}
} else { Some(()) }
}
pub fn perform_act<E: DerefMut<Target=Box<dyn Entity>>>(&self, mut e: E, act: entity::Action) {
pub fn perform_act<E: DerefMut<Target=Box<dyn Entity>>>(&self, mut e: E, act: entity::Action) -> Option<()> {
use entity::{Action::*, LinfDir};
match act {
Wait => (),
@ -160,19 +160,17 @@ impl World {
let mut rg = self.region_mut();
let tile = rg.get_or_create(p + dp);
if !tile.can_pass() {
return;
return None;
}
}
e.set_pos(p + dp);
},
Quit => {
eprintln!("{}{}",
termion::clear::All,
termion::cursor::Goto(1, 1),
);
return Some(());
panic!("Thank you for playing Wing Commander");
},
}
None
}
}
@ -182,7 +180,7 @@ mod test {
#[test]
fn room_align() -> io::Result<()> {
let mut w = World::new(0);
let mut w = World::new(0, Vec::new().into_iter());
{
let mut r = w.region_mut();
@ -213,7 +211,7 @@ mod test {
#[test]
fn world_with_entity() -> io::Result<()> {
let mut w = World::new(0);
let mut w = World::new(0, Vec::new().into_iter());
{
let mut r = w.region_mut();
@ -221,7 +219,7 @@ mod test {
}
let (width, height) = termion::terminal_size()?;
let rs = render::RenderState::new(V2i(width as isize, height as isize));
let mut rs = render::RenderState::new(V2i(width as isize, height as isize));
let mut out = std::io::stdout();
#[derive(Debug)]
@ -235,6 +233,6 @@ mod test {
w.add_entity(Box::new(Ent));
w.render(&rs, &mut out)
w.render(&mut rs, &mut out)
}
}

98
src/world/render.rs

@ -7,25 +7,23 @@ use rogue_util::grid::region::Region;
#[derive(Debug)]
pub struct Neighbors<'a, T: Debug> {
ul: &'a T, u: &'a T, ur: &'a T,
l: &'a T, this: &'a T, r: &'a T,
dl: &'a T, d: &'a T, dr: &'a T,
this_exists: bool,
ul: Option<&'a T>, u: Option<&'a T>, ur: Option<&'a T>,
l: Option<&'a T>, this: Option<&'a T>, r: Option<&'a T>,
dl: Option<&'a T>, d: Option<&'a T>, dr: Option<&'a T>,
}
impl<'a, T: Debug + Default> Neighbors<'a, T> {
pub fn from_region_pos<'r: 'a>(r: &'r Region<T>, p: V2i, def: &'a T) -> Neighbors<'a, T> {
Neighbors {
ul: r.get(p + V2i(-1, -1)).unwrap_or(def),
u: r.get(p + V2i(0, -1)).unwrap_or(def),
ur: r.get(p + V2i(1, -1)).unwrap_or(def),
l: r.get(p + V2i(-1, 0)).unwrap_or(def),
this: r.get(p).unwrap_or(def),
r: r.get(p + V2i(1, 0)).unwrap_or(def),
dl: r.get(p + V2i(-1, 1)).unwrap_or(def),
d: r.get(p + V2i(0, 1)).unwrap_or(def),
dr: r.get(p + V2i(1, 1)).unwrap_or(def),
this_exists: r.get(p).is_some(),
ul: r.get(p + V2i(-1, -1)),
u: r.get(p + V2i(0, -1)),
ur: r.get(p + V2i(1, -1)),
l: r.get(p + V2i(-1, 0)),
this: r.get(p),
r: r.get(p + V2i(1, 0)),
dl: r.get(p + V2i(-1, 1)),
d: r.get(p + V2i(0, 1)),
dr: r.get(p + V2i(1, 1)),
}
}
}
@ -33,7 +31,7 @@ impl<'a, T: Debug + Default> Neighbors<'a, T> {
impl<'a, T: Debug> Neighbors<'a, T> {
pub fn for_each<F>(&self, mut f: F)
where
F: FnMut(&'a T)
F: FnMut(Option<&'a T>)
{
f(self.ul); f(self.u); f(self.ur);
f(self.l); f(self.this); f(self.r);
@ -44,7 +42,7 @@ impl<'a, T: Debug> Neighbors<'a, T> {
pub trait Renderer {
type Tile: Debug;
fn render<'a, 's: 'a>(&'s mut self, neighbors: Neighbors<'a, Self::Tile>) -> char;
fn render<'a, 's: 'a>(&'s mut self, neighbors: Neighbors<'a, Self::Tile>) -> u8;
}
pub struct BasicRenderer;
@ -52,10 +50,10 @@ pub struct BasicRenderer;
impl Renderer for BasicRenderer {
type Tile = Tile;
fn render<'a, 's: 'a>(&'s mut self, neighbors: Neighbors<'a, Tile>) -> char {
match neighbors.this.content {
Content::Air => '.',
Content::Stone => ' ',
fn render<'a, 's: 'a>(&'s mut self, neighbors: Neighbors<'a, Tile>) -> u8 {
match neighbors.this.map(|t| t.content) {
Some(Content::Air) => b'.',
Some(Content::Stone) | None => b' ',
}
}
}
@ -65,10 +63,10 @@ pub struct InvertRenderer;
impl Renderer for InvertRenderer {
type Tile = Tile;
fn render<'a, 's: 'a>(&'s mut self, neighbors: Neighbors<'a, Tile>) -> char {
match neighbors.this.content {
Content::Air => ' ',
Content::Stone => '#',
fn render<'a, 's: 'a>(&'s mut self, neighbors: Neighbors<'a, Tile>) -> u8 {
match neighbors.this.map(|t| t.content) {
Some(Content::Air) => b' ',
Some(Content::Stone) | None => b'#',
}
}
}
@ -78,16 +76,18 @@ pub struct EdgeRenderer;
impl Renderer for EdgeRenderer {
type Tile = Tile;
fn render<'a, 's: 'a>(&'s mut self, neighbors: Neighbors<'a, Tile>) -> char {
match neighbors.this.content {
Content::Air => '.',
Content::Stone => {
fn render<'a, 's: 'a>(&'s mut self, neighbors: Neighbors<'a, Tile>) -> u8 {
match neighbors.this.map(|t| t.content) {
Some(Content::Air) => b'.',
None => b' ',
Some(Content::Stone) => {
let mut air_count = 0;
neighbors.for_each(|t| if t.content == Content::Air { air_count += 1; });
neighbors.for_each(
|t| if let Some(Tile { content: Content::Air, .. }) = t { air_count += 1; });
if air_count > 0 {
'#'
b'#'
} else {
' '
b' '
}
},
}
@ -95,7 +95,7 @@ impl Renderer for EdgeRenderer {
}
pub struct RenderState {
term_size: V2i,
term_size: RefCell<V2i>,
center: V2i,
}
@ -103,7 +103,8 @@ impl RenderState {
pub fn new_centered(term_size: V2i, center: V2i) -> RenderState {
debug_assert!(term_size.is_strict_q1());
RenderState {
term_size, center,
term_size: RefCell::new(term_size),
center,
}
}
@ -111,15 +112,18 @@ impl RenderState {
pub fn center(&self) -> V2i { self.center }
pub fn term_size(&self) -> V2i { self.term_size }
pub fn term_size(&self) -> V2i { self.term_size.borrow().clone() }
pub fn refresh_term_size(&self) -> io::Result<()> { let (w, h) = termion::terminal_size()?; *self.term_size.borrow_mut() = V2i(w as isize, h as isize); Ok(()) }
pub fn recenter(&mut self, c: V2i) {
self.center = c;
}
pub fn screen_rect(&self) -> R2i {
let halfsize = self.term_size / V2i(2, 2);
R2i::origin_dim(self.center - halfsize, self.term_size)
let ts = self.term_size();
let halfsize = ts / V2i(2, 2);
R2i::origin_dim(self.center - halfsize, ts)
}
pub fn render<R, W>(&self, region: &Region<Tile>, renderer: &mut R, out: &mut W) -> io::Result<()>
@ -127,31 +131,25 @@ impl RenderState {
R: Renderer<Tile=Tile>,
W: Write
{
self.refresh_term_size();
let screen = self.screen_rect();
write!(out, "{}{}",
//termion::clear::All,
"",
termion::clear::All,
termion::cursor::Goto(1, 1),
)?;
let mut last_pt: Option<V2i> = None;
let def_tile = Tile::default();
let mut screen_buffer: Vec<u8> = Vec::new();
for pt in &screen {
if let Some(l) = last_pt {
if l.1 != pt.1 {
write!(out, "\r\n")?;
}
}
last_pt = Some(pt);
write!(out, "{}", renderer.render(
Neighbors::from_region_pos(region, pt, &def_tile)
))?;
screen_buffer.push(renderer.render(Neighbors::from_region_pos(region, pt, &def_tile)));
}
write!(out, "{}", unsafe { core::str::from_utf8_unchecked(&screen_buffer) });
Ok(())
}

Loading…
Cancel
Save