Traverse the dungeon tile structure to create the rooms, and align the stairs.

This commit is contained in:
Avi Weinstock 2021-06-22 20:56:37 -04:00
parent c6bb61f2e6
commit c8383aba38
4 changed files with 153 additions and 100 deletions

View File

@ -154,8 +154,8 @@ impl Site {
};
s.apply_supplement(dynamic_rng, wpos2d, get_column, supplement, economy)
},
SiteKind::Dungeon(d) => {}, /* d.apply_supplement(dynamic_rng, wpos2d, get_column,
* supplement), */
SiteKind::Dungeon(d) => {}, /* d.apply_supplement(dynamic_rng, wpos2d, get_column, */
// supplement),
SiteKind::Castle(c) => c.apply_supplement(dynamic_rng, wpos2d, get_column, supplement),
SiteKind::Refactor(_) => {},
SiteKind::Tree(_) => {},

View File

@ -158,7 +158,7 @@ impl Fill {
canvas.index,
*sb,
pos - tr,
info.wpos,
p.get_bounds().center().xy(),
*seed,
col_sample,
Block::air,

View File

@ -753,7 +753,6 @@ impl Site {
}
}
}
tracing::info!("{:?}: {:?}", canvas.wpos(), plots.len());
let mut plots_to_render = plots.into_iter().collect::<Vec<_>>();
plots_to_render.sort_unstable();
@ -762,16 +761,7 @@ impl Site {
let (prim_tree, fills) = match &self.plots[plot].kind {
PlotKind::House(house) => house.render_collect(self),
PlotKind::Castle(castle) => castle.render_collect(self),
PlotKind::Dungeon(dungeon) => {
let (prim_tree, fills) = dungeon.render_collect(self);
tracing::info!(
"{:?}: {:?} {:?}",
dungeon.name(),
prim_tree.ids().count(),
fills.len()
);
(prim_tree, fills)
},
PlotKind::Dungeon(dungeon) => dungeon.render_collect(self),
_ => continue,
};

View File

@ -1169,7 +1169,7 @@ pub fn spiral_staircase(
stretch: f32,
) -> Box<dyn Fn(Vec3<i32>) -> bool> {
Box::new(move |pos: Vec3<i32>| {
let pos = pos + origin;
let pos = pos - origin;
if (pos.xy().magnitude_squared() as f32) < inner_radius.powi(2) {
true
} else if (pos.xy().magnitude_squared() as f32) < radius.powi(2) {
@ -1211,104 +1211,31 @@ pub fn wall_staircase(
})
}
impl SiteStructure for Dungeon {
impl Floor {
fn render<F: FnMut(Primitive) -> Id<Primitive>, G: FnMut(Id<Primitive>, Fill)>(
&self,
site: &site2::Site,
mut prim: F,
mut fill: G,
dungeon: &Dungeon,
floor_z: i32,
) {
//let rpos = pos - self.tile_offset * TILE_SIZE;
//let tile_pos = rpos.map(|e| e.div_euclid(TILE_SIZE));
//let tile_center = tile_pos * TILE_SIZE + TILE_SIZE / 2;
//let rtile_pos = rpos - tile_center;
let vacant = Block::air(SpriteKind::Empty);
let stone_red = Block::new(BlockKind::Rock, Rgb::new(255, 0, 0));
let stone_orange = Block::new(BlockKind::Rock, Rgb::new(255, 128, 0));
let stone_green = Block::new(BlockKind::Rock, Rgb::new(0, 255, 0));
let stone_cyan = Block::new(BlockKind::Rock, Rgb::new(0, 255, 255));
let stone_blue = Block::new(BlockKind::Rock, Rgb::new(0, 0, 255));
//let colors = &index.colors.site.dungeon;
let vacant = Block::air(SpriteKind::Empty);
//let stone = Block::new(BlockKind::Rock, colors.stone.into());
let stone_red = Block::new(BlockKind::Rock, Rgb::new(255, 0, 0));
let stone_green = Block::new(BlockKind::Rock, Rgb::new(0, 255, 0));
let stone_blue = Block::new(BlockKind::Rock, Rgb::new(0, 0, 255));
use inline_tweak::tweak;
let cutout_size = tweak!(9);
let origin = self.origin.with_z(self.alt);
let cutout = prim(Primitive::Aabb(Aabb {
min: origin - Vec2::broadcast(cutout_size * 7).with_z(self.alt - 1),
max: origin + Vec2::broadcast(cutout_size * 7).with_z(100),
}));
fill(cutout, Fill::Block(vacant));
let stairs_inf = prim(Primitive::Sampling(wall_staircase(
origin,
TILE_SIZE as f32 / 2.0,
tweak!(27.0),
)));
let stairs_radius = 7;
let bounding_box = prim(Primitive::Aabb(Aabb {
min: origin - Vec3::new(stairs_radius, stairs_radius, self.alt - 1),
max: origin + Vec3::new(stairs_radius, stairs_radius, 400),
}));
//let stairs_inf = prim(Primitive::Sampling(Box::new(|_| true)));
let stairs = prim(Primitive::And(bounding_box, stairs_inf));
let stairs_tr1 = prim(Primitive::Translate(stairs, Vec3::unit_z()));
let stairs_tr2 = prim(Primitive::Translate(stairs, Vec3::broadcast(tweak!(-16))));
/*let stairs = prim(Primitive::Cone(Aabb {
min: self.origin.with_z(self.alt) - Vec3::broadcast(16),
max: self.origin.with_z(self.alt + 100) + Vec3::broadcast(16),
}));*/
fill(stairs, Fill::Block(stone_red));
fill(stairs_tr1, Fill::Block(stone_green));
fill(stairs_tr2, Fill::Block(stone_blue));
lazy_static! {
pub static ref ENTRANCES: AssetHandle<StructuresGroup> =
Structure::load_group("dungeon_entrances");
}
let entrances = ENTRANCES.read();
let entrance = entrances[self.seed as usize % entrances.len()].clone();
/*let entrance_aabb = prim(Primitive::Aabb(entrance.get_bounds()));
let entrance = prim(Primitive::Sampling(Box::new(move |pos| {
entrance
.get(pos)
.map_or(false, |b| !matches!(b, StructureBlock::None))
let floor_sprite = prim(Primitive::Sampling(Box::new(|pos| {
RandomField::new(7331).chance(Vec3::from(pos), 0.001)
})));
let entrance = prim(Primitive::And(entrance, entrance_aabb));
let entrance = prim(Primitive::Translate(entrance, origin));
fill(entrance, Fill::Block(stone_red));*/
let entrance_prim = prim(Primitive::Prefab(entrance.clone()));
let entrance_prim = prim(Primitive::Translate(entrance_prim, origin));
let entrance_prim = prim(Primitive::Diff(entrance_prim, bounding_box));
//fill(entrance_prim, Fill::Block(stone_red));
fill(entrance_prim, Fill::Prefab(entrance, origin, self.seed));
/*let make_staircase = move |kind: &StairsKind,
pos: Vec3<i32>,
radius: f32,
inner_radius: f32,
stretch: f32,
height_limit: i32| {
match kind {
StairsKind::Spiral => make_spiral_staircase(pos, radius, inner_radius, stretch),
StairsKind::WallSpiral => {
make_wall_staircase(pos, radius, stretch * 3.0, height_limit)
},
}
};
let wall_thickness = 3.0;
let dist_to_wall = self
.nearest_wall(rpos)
.map(|nearest| (nearest.distance_squared(rpos) as f32).sqrt())
.unwrap_or(TILE_SIZE as f32);
let tunnel_dist =
1.0 - (dist_to_wall - wall_thickness).max(0.0) / (TILE_SIZE as f32 - wall_thickness);
let floor_sprite = if RandomField::new(7331).chance(Vec3::from(pos), 0.001) {
/*let floor_sprite = if RandomField::new(7331).chance(Vec3::from(pos), 0.001) {
BlockMask::new(
with_sprite(
match (RandomField::new(1337).get(Vec3::from(pos)) / 2) % 30 {
@ -1341,8 +1268,114 @@ impl SiteStructure for Dungeon {
}
} else {
vacant
};*/
let aabb_edges = |prim: &mut F, aabb: Aabb<_>| {
let f = |prim: &mut F, ret, vec| {
let sub = prim(Primitive::Aabb(Aabb {
min: aabb.min + vec,
max: aabb.max - vec,
}));
prim(Primitive::Diff(ret, sub))
};
let mut ret = prim(Primitive::Aabb(aabb));
ret = f(prim, ret, Vec3::new(1, 0, 0));
ret = f(prim, ret, Vec3::new(0, 1, 0));
ret = f(prim, ret, Vec3::new(0, 0, 1));
ret
};
fn aabr_with_z<T>(aabr: Aabr<T>, z: std::ops::Range<T>) -> Aabb<T> {
Aabb {
min: aabr.min.with_z(z.start),
max: aabr.max.with_z(z.end),
}
}
let mut stairs_bb = prim(Primitive::Empty);
let mut stairs = prim(Primitive::Empty);
for (tile_pos, tile) in self.tiles.iter() {
let tile_corner = dungeon.origin + TILE_SIZE * (self.tile_offset + tile_pos);
let tile_aabr = Aabr {
min: tile_corner,
max: tile_corner + Vec2::broadcast(TILE_SIZE),
};
let (color, mut height, room) = match tile {
Tile::UpStair(room, kind) => {
let center = (tile_corner + Vec2::broadcast(TILE_SIZE) / 2).with_z(floor_z);
let radius = TILE_SIZE as f32 / 2.0;
let aabb =
aabr_with_z(tile_aabr, floor_z + 1..floor_z + self.total_depth() + 1);
let bb = prim(match kind {
StairsKind::Spiral => Primitive::Cylinder(aabb),
StairsKind::WallSpiral => Primitive::Aabb(aabb),
});
let stair = prim(Primitive::Sampling(match kind {
StairsKind::Spiral => spiral_staircase(center, radius, 0.5, 9.0),
StairsKind::WallSpiral => wall_staircase(center, radius, 27.0),
}));
let stair = prim(Primitive::And(bb, stair));
stairs_bb = prim(Primitive::Or(stairs_bb, bb));
stairs = prim(Primitive::Or(stairs, stair));
(stone_cyan, self.hollow_depth, Some(room))
},
Tile::DownStair(room) => (stone_green, self.hollow_depth, Some(room)),
Tile::Room(room) => (stone_blue, self.hollow_depth, Some(room)),
Tile::Tunnel => (stone_orange, self.hollow_depth / 2, None),
//Tile::Solid => (vacant, self.total_depth(), None),
Tile::Solid => continue,
};
if let Some(room) = room.map(|i| self.rooms.get(*i)) {
height = height.min(room.height);
}
let tile_air = prim(Primitive::Aabb(aabr_with_z(
tile_aabr,
floor_z..floor_z + height,
)));
fill(tile_air, Fill::Block(vacant));
let tile_edges =
aabb_edges(&mut prim, aabr_with_z(tile_aabr, floor_z..floor_z + height));
let floor_prim = prim(Primitive::Aabb(aabr_with_z(
tile_aabr,
floor_z..floor_z + 1,
)));
fill(floor_prim, Fill::Block(color));
let sprite_layer = prim(Primitive::Aabb(aabr_with_z(
tile_aabr,
floor_z + 1..floor_z + 2,
)));
let sprite_intersection = prim(Primitive::And(floor_sprite, sprite_layer));
fill(sprite_intersection, Fill::Block(stone_red));
fill(tile_edges, Fill::Block(Block::air(SpriteKind::Lantern)));
}
fill(stairs_bb, Fill::Block(vacant));
fill(stairs, Fill::Block(stone_red));
/*let make_staircase = move |kind: &StairsKind,
pos: Vec3<i32>,
radius: f32,
inner_radius: f32,
stretch: f32,
height_limit: i32| {
match kind {
StairsKind::Spiral => make_spiral_staircase(pos, radius, inner_radius, stretch),
StairsKind::WallSpiral => {
make_wall_staircase(pos, radius, stretch * 3.0, height_limit)
},
}
};
let wall_thickness = 3.0;
let dist_to_wall = self
.nearest_wall(rpos)
.map(|nearest| (nearest.distance_squared(rpos) as f32).sqrt())
.unwrap_or(TILE_SIZE as f32);
let tunnel_dist =
1.0 - (dist_to_wall - wall_thickness).max(0.0) / (TILE_SIZE as f32 - wall_thickness);
let tunnel_height = if self.final_level { 16.0 } else { 8.0 };
let pillar_thickness: i32 = 4;
@ -1451,3 +1484,33 @@ impl SiteStructure for Dungeon {
}*/
}
}
impl SiteStructure for Dungeon {
fn render<F: FnMut(Primitive) -> Id<Primitive>, G: FnMut(Id<Primitive>, Fill)>(
&self,
site: &site2::Site,
mut prim: F,
mut fill: G,
) {
let origin = (self.origin + Vec2::broadcast(TILE_SIZE / 2)).with_z(self.alt + ALT_OFFSET);
lazy_static! {
pub static ref ENTRANCES: AssetHandle<StructuresGroup> =
Structure::load_group("dungeon_entrances");
}
let entrances = ENTRANCES.read();
let entrance = entrances[self.seed as usize % entrances.len()].clone();
let entrance_prim = prim(Primitive::Prefab(entrance.clone()));
let entrance_prim = prim(Primitive::Translate(entrance_prim, origin));
fill(entrance_prim, Fill::Prefab(entrance, origin, self.seed));
let mut z = self.alt + ALT_OFFSET;
for floor in &self.floors {
z -= floor.total_depth();
floor.render(&mut prim, &mut fill, &self, z);
}
}
}