Basic town house generation

This commit is contained in:
Joshua Barretto 2020-04-11 01:09:01 +01:00
parent fd3ffdf28b
commit 8499143f77
6 changed files with 111 additions and 36 deletions

View File

@ -14,8 +14,12 @@ use common::{
store::{Id, Store},
path::Path,
astar::Astar,
spiral::Spiral2d,
};
use crate::{
sim::{WorldSim, SimChunk},
site::{Site as WorldSite, Settlement},
};
use crate::sim::{WorldSim, SimChunk};
const CARDINALS: [Vec2<i32>; 4] = [
Vec2::new(1, 0),
@ -79,10 +83,22 @@ impl Civs {
// Temporary!
for track in this.tracks.iter() {
for loc in track.path.iter() {
sim.get_mut(*loc).unwrap().place = Some(this.civs.iter().next().unwrap().homeland);
ctx.sim.get_mut(*loc).unwrap().place = Some(this.civs.iter().next().unwrap().homeland);
}
}
// Place sites in world
for site in this.sites.iter() {
let wpos = site.center * Vec2::from(TerrainChunkSize::RECT_SIZE).map(|e: u32| e as i32);
let settlement = WorldSite::from(Settlement::generate(wpos, Some(ctx.sim), ctx.rng));
for pos in Spiral2d::new().map(|offs| site.center + offs).take(32usize.pow(2)) {
ctx.sim
.get_mut(pos)
.map(|chunk| chunk.sites.push(settlement.clone()));
}
println!("Placed site at {:?}", site.center);
}
this.display_info();
this

View File

@ -1451,6 +1451,7 @@ impl WorldSim {
*/
// Stage 2 - towns!
/*
let chunk_idx_center = |e: Vec2<i32>| {
e.map2(TerrainChunkSize::RECT_SIZE, |e, sz: u32| {
e * sz as i32 + sz as i32 / 2
@ -1464,12 +1465,9 @@ impl WorldSim {
chunk_idx_center(WORLD_SIZE.map(|e| e as i32)),
)
.map_init(
|| Box::new(BlockGen::new(ColumnGen::new(self))),
|mut block_gen, (pos, seed)| {
|| (),
|_, (pos, seed)| {
let mut rng = ChaChaRng::from_seed(seed_expan::rng_state(seed));
// println!("Town: {:?}", town);
//TownState::generate(pos, &mut block_gen, &mut rng).map(|t| (pos,
// Arc::new(t)))
(
pos,
Site::from(Settlement::generate(pos, Some(self), &mut rng)),
@ -1496,6 +1494,7 @@ impl WorldSim {
chunk.sites.push(site.clone());
}
});
*/
// Create waypoints
const WAYPOINT_EVERY: usize = 16;

View File

@ -52,7 +52,7 @@ impl Archetype for House {
let empty = Some(Some(Block::empty()));
let ceil_height = 6;
let width = 3 + branch.locus + if profile.y >= ceil_height { 1 } else { 0 };
let width = -3 + branch.locus + if profile.y >= ceil_height { 1 } else { 0 };
let foundation_height = 0 - (dist - width - 1).max(0);
let roof_height = 8 + width;
@ -115,7 +115,7 @@ impl Archetype for House {
};
// Window
if (frame_bounds.size() + 1).reduce_min() > 2 {
if (frame_bounds.size() + 1).reduce_min() > 2 { // Window frame is large enough for a window
let surface_pos = Vec2::new(bound_offset.x, profile.y);
if window_bounds.contains_point(surface_pos) {
return empty;

View File

@ -30,12 +30,12 @@ impl<A: Archetype> Building<A> {
root: Branch {
len,
attr: A::Attr::default(),
locus: 2 + rng.gen_range(0, 5),
locus: 8 + rng.gen_range(0, 5),
children: (0..rng.gen_range(0, 4))
.map(|_| (rng.gen_range(0, len + 1), Branch {
.map(|_| (rng.gen_range(-5, len + 5).clamped(0, len.max(1) - 1), Branch {
len: rng.gen_range(5, 12) * if rng.gen() { 1 } else { -1 },
attr: A::Attr::default(),
locus: 1 + rng.gen_range(0, 3),
locus: 8 + rng.gen_range(0, 3),
children: Vec::new(),
}))
.collect(),
@ -49,8 +49,8 @@ impl<A: Archetype> Building<A> {
pub fn bounds_2d(&self) -> Aabr<i32> {
let b = self.skel.bounds();
Aabr {
min: Vec2::from(self.origin) + b.min - 14,
max: Vec2::from(self.origin) + b.max + 14,
min: Vec2::from(self.origin) + b.min,
max: Vec2::from(self.origin) + b.max,
}
}

View File

@ -52,8 +52,12 @@ impl<T> Skeleton<T> {
pub fn bounds(&self) -> Aabr<i32> {
let mut bounds = Aabr::new_empty(self.ori.dir() * self.offset);
self.for_each(|node, ori, branch| {
bounds.expand_to_contain(Aabr::new_empty(node - ori.flip().dir() * branch.locus)
.expanded_to_contain_point(node + ori.dir() * branch.len + ori.flip().dir() * branch.locus));
let node2 = node + ori.dir() * branch.len;
let a = node.map2(node2, |a, b| a.min(b)) - branch.locus;
let b = node.map2(node2, |a, b| a.max(b)) + branch.locus;
bounds.expand_to_contain_point(a);
bounds.expand_to_contain_point(b);
});
bounds
}

View File

@ -89,6 +89,14 @@ pub struct Structure {
kind: StructureKind,
}
impl Structure {
pub fn bounds_2d(&self) -> Aabr<i32> {
match &self.kind {
StructureKind::House(house) => house.bounds_2d(),
}
}
}
pub struct Settlement {
origin: Vec2<i32>,
land: Land,
@ -128,7 +136,7 @@ impl Settlement {
//this.place_river(rng);
this.place_farms(&mut ctx);
this.place_town(ctx.rng);
this.place_town(&mut ctx);
this.place_paths(ctx.rng);
this
@ -229,10 +237,10 @@ impl Settlement {
}
}
pub fn place_town(&mut self, rng: &mut impl Rng) {
pub fn place_town(&mut self, ctx: &mut GenCtx<impl Rng>) {
const PLOT_COUNT: usize = 2;
let mut origin = Vec2::new(rng.gen_range(-2, 3), rng.gen_range(-2, 3));
let mut origin = Vec2::new(ctx.rng.gen_range(-2, 3), ctx.rng.gen_range(-2, 3));
for i in 0..PLOT_COUNT {
if let Some(base_tile) = self.land.find_tile_near(origin, |plot| match plot {
@ -244,6 +252,43 @@ impl Settlement {
.plot_at_mut(base_tile)
.map(|plot| *plot = Plot::Town);
for _ in 0..ctx.rng.gen_range(10, 30) {
for _ in 0..10 {
let house_pos = base_tile.map(|e| e * AREA_SIZE as i32 + AREA_SIZE as i32 / 2)
+ Vec2::<i32>::zero().map(|_| ctx.rng.gen_range(-(AREA_SIZE as i32) * 3, AREA_SIZE as i32 * 3));
if let Some(Plot::Town) = self.land
.plot_at(house_pos.map(|e| e.div_euclid(AREA_SIZE as i32)))
{} else {
continue;
}
let structure = Structure {
kind: StructureKind::House(HouseBuilding::generate(ctx.rng, Vec3::new(
house_pos.x,
house_pos.y,
ctx.sim
.and_then(|sim| sim.get_alt_approx(self.origin + house_pos))
.unwrap_or(0.0)
.ceil() as i32,
))),
};
let bounds = structure.bounds_2d();
// Check for collision with other structures
if self.structures
.iter()
.any(|s| s.bounds_2d().collides_with_aabr(bounds))
{
continue;
}
self.structures.push(structure);
break;
}
}
if i == 0 {
/*
for dir in CARDINALS.iter() {
@ -315,21 +360,21 @@ impl Settlement {
self.land.set(base_tile, farmhouse);
// Farmhouses
for _ in 0..ctx.rng.gen_range(1, 3) {
let house_pos = base_tile.map(|e| e * AREA_SIZE as i32 + AREA_SIZE as i32 / 2)
+ Vec2::new(ctx.rng.gen_range(-16, 16), ctx.rng.gen_range(-16, 16));
// for _ in 0..ctx.rng.gen_range(1, 3) {
// let house_pos = base_tile.map(|e| e * AREA_SIZE as i32 + AREA_SIZE as i32 / 2)
// + Vec2::new(ctx.rng.gen_range(-16, 16), ctx.rng.gen_range(-16, 16));
self.structures.push(Structure {
kind: StructureKind::House(HouseBuilding::generate(ctx.rng, Vec3::new(
house_pos.x,
house_pos.y,
ctx.sim
.and_then(|sim| sim.get_alt_approx(self.origin + house_pos))
.unwrap_or(0.0)
.ceil() as i32,
))),
});
}
// self.structures.push(Structure {
// kind: StructureKind::House(HouseBuilding::generate(ctx.rng, Vec3::new(
// house_pos.x,
// house_pos.y,
// ctx.sim
// .and_then(|sim| sim.get_alt_approx(self.origin + house_pos))
// .unwrap_or(0.0)
// .ceil() as i32,
// ))),
// });
// }
// Fields
let farmland = self.farms.insert(Farm { base_tile });
@ -463,13 +508,24 @@ impl Settlement {
// Apply structures
for structure in &self.structures {
let bounds = structure.bounds_2d();
// Skip this structure if it's not near this chunk
if !bounds.collides_with_aabr(Aabr {
min: wpos2d - self.origin,
max: wpos2d - self.origin + vol.size_xy().map(|e| e as i32),
}) {
continue;
}
match &structure.kind {
StructureKind::House(b) => {
let centre = b.bounds_2d().center();
let bounds = b.bounds();
for x in bounds.min.x..bounds.max.x {
for y in bounds.min.y..bounds.max.y {
for z in bounds.min.z..bounds.max.z {
for x in bounds.min.x..bounds.max.x + 1 {
for y in bounds.min.y..bounds.max.y + 1 {
for z in bounds.min.z..bounds.max.z + 1 {
let rpos = Vec3::new(x, y, z);
let wpos = Vec3::from(self.origin) + rpos;
let coffs = wpos - Vec3::from(wpos2d);