Wider roads, better structure

This commit is contained in:
Joshua Barretto 2021-02-19 18:43:17 +00:00
parent 1dab08075e
commit cd97a4b2fc

View File

@ -67,14 +67,23 @@ impl Site {
} }
} }
pub fn create_road(&mut self, land: &Land, rng: &mut impl Rng, a: Vec2<i32>, b: Vec2<i32>) -> Option<Id<Plot>> { pub fn create_road(&mut self, land: &Land, rng: &mut impl Rng, a: Vec2<i32>, b: Vec2<i32>, w: i32) -> Option<Id<Plot>> {
const MAX_ITERS: usize = 4096; const MAX_ITERS: usize = 4096;
let heuristic = |tile: &Vec2<i32>| if self.tiles.get(*tile).is_obstacle() { 100.0 } else { 0.0 }; let heuristic = |tile: &Vec2<i32>| {
for y in 0..w {
for x in 0..w {
if self.tiles.get(*tile + Vec2::new(x, y)).is_obstacle() {
return 100.0;
}
}
}
(tile.distance_squared(b) as f32).sqrt()
};
let path = Astar::new(MAX_ITERS, a, &heuristic, DefaultHashBuilder::default()).poll( let path = Astar::new(MAX_ITERS, a, &heuristic, DefaultHashBuilder::default()).poll(
MAX_ITERS, MAX_ITERS,
&heuristic, &heuristic,
|tile| { let tile = *tile; CARDINALS.iter().map(move |dir| tile + *dir) }, |tile| { let tile = *tile; CARDINALS.iter().map(move |dir| tile + *dir) },
|a, b| (a.distance_squared(*b) as f32).sqrt(), |a, b| rng.gen_range(1.0..1.5),
|tile| *tile == b, |tile| *tile == b,
).into_path()?; ).into_path()?;
@ -89,11 +98,15 @@ impl Site {
self.roads.push(plot); self.roads.push(plot);
for &tile in path.iter() { for &tile in path.iter() {
self.tiles.set(tile, Tile { for y in 0..w {
for x in 0..w {
self.tiles.set(tile + Vec2::new(x, y), Tile {
kind: TileKind::Road, kind: TileKind::Road,
plot: Some(plot), plot: Some(plot),
}); });
} }
}
}
Some(plot) Some(plot)
} }
@ -101,21 +114,24 @@ impl Site {
pub fn find_aabr(&mut self, search_pos: Vec2<i32>, area_range: Range<u32>, min_dims: Extent2<u32>) -> Option<(Aabr<i32>, Vec2<i32>)> { pub fn find_aabr(&mut self, search_pos: Vec2<i32>, area_range: Range<u32>, min_dims: Extent2<u32>) -> Option<(Aabr<i32>, Vec2<i32>)> {
self.tiles.find_near( self.tiles.find_near(
search_pos, search_pos,
|center, _| if CARDINALS.iter().any(|&dir| self.tiles.get(center + dir).kind == TileKind::Road) { |center, _| self.tiles.grow_aabr(center, area_range.clone(), min_dims)
self.tiles.grow_aabr(center, area_range.clone(), min_dims).ok() .ok()
} else { .filter(|aabr| {
None (aabr.min.x..aabr.max.x).any(|x| self.tiles.get(Vec2::new(x, aabr.min.y - 1)).kind == TileKind::Road)
}, || (aabr.min.x..aabr.max.x).any(|x| self.tiles.get(Vec2::new(x, aabr.max.y)).kind == TileKind::Road)
|| (aabr.min.y..aabr.max.y).any(|y| self.tiles.get(Vec2::new(aabr.min.x - 1, y)).kind == TileKind::Road)
|| (aabr.min.y..aabr.max.y).any(|y| self.tiles.get(Vec2::new(aabr.max.x, y)).kind == TileKind::Road)
}),
) )
} }
pub fn find_roadside_aabr(&mut self, rng: &mut impl Rng, area_range: Range<u32>, min_dims: Extent2<u32>) -> Option<(Aabr<i32>, Vec2<i32>)> { pub fn find_roadside_aabr(&mut self, rng: &mut impl Rng, area_range: Range<u32>, min_dims: Extent2<u32>) -> Option<(Aabr<i32>, Vec2<i32>)> {
let dir = Vec2::<f32>::zero().map(|_| rng.gen_range(-1.0..1.0)).normalized(); let dir = Vec2::<f32>::zero().map(|_| rng.gen_range(-1.0..1.0)).normalized();
let search_pos = if rng.gen() { let search_pos = if rng.gen() {
self.plot(*self.plazas.choose(rng)?).root_tile + (dir * 5.0).map(|e: f32| e.round() as i32) self.plot(*self.plazas.choose(rng)?).root_tile + (dir * 4.0).map(|e: f32| e.round() as i32)
} else { } else {
if let PlotKind::Road(path) = &self.plot(*self.roads.choose(rng)?).kind { if let PlotKind::Road(path) = &self.plot(*self.roads.choose(rng)?).kind {
*path.nodes().choose(rng)? + (dir * 1.5).map(|e: f32| e.round() as i32) *path.nodes().choose(rng)? + (dir * 1.0).map(|e: f32| e.round() as i32)
} else { } else {
unreachable!() unreachable!()
} }
@ -128,11 +144,11 @@ impl Site {
let pos = attempt(32, || { let pos = attempt(32, || {
self.plazas self.plazas
.choose(rng) .choose(rng)
.map(|&p| self.plot(p).root_tile + Vec2::new(rng.gen_range(-20..20), rng.gen_range(-20..20))) .map(|&p| self.plot(p).root_tile + (Vec2::new(rng.gen_range(-1.0..1.0), rng.gen_range(-1.0..1.0)).normalized() * 24.0).map(|e| e as i32))
.filter(|&tile| self .filter(|&tile| self
.plazas .plazas
.iter() .iter()
.all(|&p| self.plot(p).root_tile.distance_squared(tile) > 16i32.pow(2)) .all(|&p| self.plot(p).root_tile.distance_squared(tile) > 20i32.pow(2))
&& rng.gen_range(0..48) > tile.map(|e| e.abs()).reduce_max()) && rng.gen_range(0..48) > tile.map(|e| e.abs()).reduce_max())
}) })
.unwrap_or_else(Vec2::zero); .unwrap_or_else(Vec2::zero);
@ -152,13 +168,14 @@ impl Site {
}); });
let mut already_pathed = vec![plaza]; let mut already_pathed = vec![plaza];
for _ in 0..2 { // One major, one minor road
for width in (1..=2).rev() {
if let Some(&p) = self.plazas if let Some(&p) = self.plazas
.iter() .iter()
.filter(|p| !already_pathed.contains(p)) .filter(|p| !already_pathed.contains(p))
.min_by_key(|&&p| self.plot(p).root_tile.distance_squared(pos)) .min_by_key(|&&p| self.plot(p).root_tile.distance_squared(pos))
{ {
self.create_road(land, rng, self.plot(p).root_tile, pos); self.create_road(land, rng, self.plot(p).root_tile, pos, width);
already_pathed.push(p); already_pathed.push(p);
} else { } else {
break; break;
@ -179,7 +196,7 @@ impl Site {
let build_chance = Lottery::from(vec![ let build_chance = Lottery::from(vec![
(1.0, 0), (1.0, 0),
(48.0, 1), (48.0, 1),
(2.0, 2), (5.0, 2),
(1.0, 3), (1.0, 3),
]); ]);
@ -197,7 +214,7 @@ impl Site {
}, },
// House // House
1 => { 1 => {
let size = (2.0 + rng.gen::<f32>().powf(4.0) * 3.0).round() as u32; let size = (2.0 + rng.gen::<f32>().powf(8.0) * 3.0).round() as u32;
if let Some((aabr, _)) = attempt(10, || site.find_roadside_aabr(rng, 4..(size + 1).pow(2), Extent2::broadcast(size))) { if let Some((aabr, _)) = attempt(10, || site.find_roadside_aabr(rng, 4..(size + 1).pow(2), Extent2::broadcast(size))) {
let plot = site.create_plot(Plot { let plot = site.create_plot(Plot {
kind: PlotKind::House, kind: PlotKind::House,