Re-organzied code relating to tower and wall generation.

This commit is contained in:
Sam 2021-12-17 17:36:08 -05:00
parent 643713d8b1
commit 466a02e1cf

View File

@ -12,10 +12,8 @@ pub struct GnarlingFortification {
origin: Vec2<i32>, origin: Vec2<i32>,
radius: i32, radius: i32,
wall_radius: i32, wall_radius: i32,
// Vec2 is relative position of wall relative to site origin, bool indicates whether it is a wall_segments: Vec<(Vec2<i32>, Vec2<i32>)>,
// corner, and thus whether a tower gets constructed wall_towers: Vec<Vec2<i32>>,
ordered_wall_points: Vec<(Vec2<i32>, bool)>,
gate_index: usize,
// Structure indicates the kind of structure it is, vec2 is relative position of a hut compared // Structure indicates the kind of structure it is, vec2 is relative position of a hut compared
// to origin, ori tells which way structure should face // to origin, ori tells which way structure should face
structure_locations: Vec<(GnarlingStructure, Vec2<i32>, Ori)>, structure_locations: Vec<(GnarlingStructure, Vec2<i32>, Ori)>,
@ -36,8 +34,6 @@ impl GnarlingStructure {
} }
} }
const SECTIONS_PER_WALL_SEGMENT: usize = 3;
impl GnarlingFortification { impl GnarlingFortification {
pub fn generate(wpos: Vec2<i32>, land: &Land, rng: &mut impl Rng) -> Self { pub fn generate(wpos: Vec2<i32>, land: &Land, rng: &mut impl Rng) -> Self {
let name = String::from("Gnarling Fortification"); let name = String::from("Gnarling Fortification");
@ -70,26 +66,20 @@ impl GnarlingFortification {
let gate_index = rng.gen_range(0..wall_corners.len()); let gate_index = rng.gen_range(0..wall_corners.len());
// This adds additional points for the wall on the line between two points, let wall_segments = wall_corners
// allowing the wall to better handle slopes
let ordered_wall_points = wall_corners
.iter() .iter()
.enumerate() .enumerate()
.flat_map(|(i, point)| { .filter_map(|(i, point)| {
let next_point = if let Some(point) = wall_corners.get(i + 1) { if i == gate_index {
*point None
} else { } else {
wall_corners[0] let next_point = if let Some(point) = wall_corners.get(i + 1) {
}; *point
(0..(SECTIONS_PER_WALL_SEGMENT as i32)) } else {
.into_iter() wall_corners[0]
.map(move |a| { };
let is_start_segment = a == 0; Some((*point, next_point))
( }
point + (next_point - point) * a / (SECTIONS_PER_WALL_SEGMENT as i32),
is_start_segment,
)
})
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();
@ -161,8 +151,8 @@ impl GnarlingFortification {
origin, origin,
radius, radius,
wall_radius, wall_radius,
ordered_wall_points, wall_towers: wall_corners,
gate_index, wall_segments,
structure_locations, structure_locations,
} }
} }
@ -175,211 +165,209 @@ impl GnarlingFortification {
impl Structure for GnarlingFortification { impl Structure for GnarlingFortification {
fn render(&self, _site: &Site, land: &Land, painter: &Painter) { fn render(&self, _site: &Site, land: &Land, painter: &Painter) {
// Create outer wall // Create outer wall
for (i, (point, _is_tower)) in self.ordered_wall_points.iter().enumerate() { for (point, next_point) in self.wall_segments.iter() {
// If wall section is a gate, skip rendering the wall // This adds additional points for the wall on the line between two points,
if ((self.gate_index * SECTIONS_PER_WALL_SEGMENT) // allowing the wall to better handle slopes
..((self.gate_index + 1) * SECTIONS_PER_WALL_SEGMENT)) const SECTIONS_PER_WALL_SEGMENT: usize = 3;
.contains(&i)
{
continue;
}
// Other point of wall segment (0..(SECTIONS_PER_WALL_SEGMENT as i32))
let (next_point, _is_tower) = if let Some(point) = self.ordered_wall_points.get(i + 1) { .into_iter()
*point .map(move |a| {
} else { let get_point =
self.ordered_wall_points[0] |a| point + (next_point - point) * a / (SECTIONS_PER_WALL_SEGMENT as i32);
}; (get_point(a), get_point(a + 1))
// 2d world positions of each point in wall segment })
let start_wpos = point + self.origin; .for_each(|(point, next_point)| {
let end_wpos = next_point + self.origin; // 2d world positions of each point in wall segment
let start_wpos = point + self.origin;
let end_wpos = next_point + self.origin;
// Wall base // Wall base
let wall_depth = 3.0; let wall_depth = 3.0;
let start = start_wpos let start = start_wpos
.as_() .as_()
.with_z(land.get_alt_approx(start_wpos) - wall_depth); .with_z(land.get_alt_approx(start_wpos) - wall_depth);
let end = end_wpos let end = end_wpos
.as_() .as_()
.with_z(land.get_alt_approx(end_wpos) - wall_depth); .with_z(land.get_alt_approx(end_wpos) - wall_depth);
let wall_base_thickness = 3.0; let wall_base_thickness = 3.0;
let wall_base_height = 3.0; let wall_base_height = 3.0;
painter painter
.segment_prism( .segment_prism(
start, start,
end, end,
wall_base_thickness, wall_base_thickness,
wall_base_height + wall_depth as f32, wall_base_height + wall_depth as f32,
) )
.fill(Fill::Block(Block::new( .fill(Fill::Block(Block::new(
BlockKind::Wood, BlockKind::Wood,
Rgb::new(55, 25, 8), Rgb::new(55, 25, 8),
))); )));
// Middle of wall // Middle of wall
let start = start_wpos.as_().with_z(land.get_alt_approx(start_wpos)); let start = start_wpos.as_().with_z(land.get_alt_approx(start_wpos));
let end = end_wpos.as_().with_z(land.get_alt_approx(end_wpos)); let end = end_wpos.as_().with_z(land.get_alt_approx(end_wpos));
let wall_mid_thickness = 1.0; let wall_mid_thickness = 1.0;
let wall_mid_height = 5.0 + wall_base_height; let wall_mid_height = 5.0 + wall_base_height;
painter painter
.segment_prism(start, end, wall_mid_thickness, wall_mid_height) .segment_prism(start, end, wall_mid_thickness, wall_mid_height)
.fill(Fill::Block(Block::new( .fill(Fill::Block(Block::new(
BlockKind::Wood, BlockKind::Wood,
Rgb::new(55, 25, 8), Rgb::new(55, 25, 8),
))); )));
// Top of wall // Top of wall
let start = start_wpos let start = start_wpos
.as_() .as_()
.with_z(land.get_alt_approx(start_wpos) + wall_mid_height); .with_z(land.get_alt_approx(start_wpos) + wall_mid_height);
let end = end_wpos let end = end_wpos
.as_() .as_()
.with_z(land.get_alt_approx(end_wpos) + wall_mid_height); .with_z(land.get_alt_approx(end_wpos) + wall_mid_height);
let wall_top_thickness = 2.0; let wall_top_thickness = 2.0;
let wall_top_height = 1.0; let wall_top_height = 1.0;
painter painter
.segment_prism(start, end, wall_top_thickness, wall_top_height) .segment_prism(start, end, wall_top_thickness, wall_top_height)
.fill(Fill::Block(Block::new( .fill(Fill::Block(Block::new(
BlockKind::Wood, BlockKind::Wood,
Rgb::new(55, 25, 8), Rgb::new(55, 25, 8),
))); )));
// Wall parapets // Wall parapets
let parapet_z_offset = 1.0; let parapet_z_offset = 1.0;
let start = Vec3::new( let start = Vec3::new(
point.x as f32 * (self.wall_radius as f32 + 1.0) / (self.wall_radius as f32) point.x as f32 * (self.wall_radius as f32 + 1.0)
+ self.origin.x as f32, / (self.wall_radius as f32)
point.y as f32 * (self.wall_radius as f32 + 1.0) / (self.wall_radius as f32) + self.origin.x as f32,
+ self.origin.y as f32, point.y as f32 * (self.wall_radius as f32 + 1.0)
land.get_alt_approx(start_wpos) + wall_mid_height + wall_top_height / (self.wall_radius as f32)
- parapet_z_offset, + self.origin.y as f32,
); land.get_alt_approx(start_wpos) + wall_mid_height + wall_top_height
let end = Vec3::new( - parapet_z_offset,
next_point.x as f32 * (self.wall_radius as f32 + 1.0) / (self.wall_radius as f32) );
+ self.origin.x as f32, let end = Vec3::new(
next_point.y as f32 * (self.wall_radius as f32 + 1.0) / (self.wall_radius as f32) next_point.x as f32 * (self.wall_radius as f32 + 1.0)
+ self.origin.y as f32, / (self.wall_radius as f32)
land.get_alt_approx(end_wpos) + wall_mid_height + wall_top_height + self.origin.x as f32,
- parapet_z_offset, next_point.y as f32 * (self.wall_radius as f32 + 1.0)
); / (self.wall_radius as f32)
+ self.origin.y as f32,
land.get_alt_approx(end_wpos) + wall_mid_height + wall_top_height
- parapet_z_offset,
);
let wall_par_thickness = tweak!(0.8); let wall_par_thickness = tweak!(0.8);
let wall_par_height = 1.0; let wall_par_height = 1.0;
painter painter
.segment_prism( .segment_prism(
start, start,
end, end,
wall_par_thickness, wall_par_thickness,
wall_par_height + parapet_z_offset as f32, wall_par_height + parapet_z_offset as f32,
) )
.fill(Fill::Block(Block::new( .fill(Fill::Block(Block::new(
BlockKind::Wood, BlockKind::Wood,
Rgb::new(55, 25, 8), Rgb::new(55, 25, 8),
))); )));
})
} }
// Create towers // Create towers
self.ordered_wall_points self.wall_towers.iter().for_each(|point| {
.iter() let wpos = point + self.origin;
.filter_map(|(point, is_tower)| is_tower.then_some(point))
.for_each(|point| {
let wpos = point + self.origin;
// Tower base // Tower base
let tower_depth = 3; let tower_depth = 3;
let tower_base_pos = wpos.with_z(land.get_alt_approx(wpos) as i32 - tower_depth); let tower_base_pos = wpos.with_z(land.get_alt_approx(wpos) as i32 - tower_depth);
let tower_radius = 5.; let tower_radius = 5.;
let tower_height = 20.0; let tower_height = 20.0;
painter painter
.prim(Primitive::cylinder( .prim(Primitive::cylinder(
tower_base_pos, tower_base_pos,
tower_radius, tower_radius,
tower_depth as f32 + tower_height, tower_depth as f32 + tower_height,
)) ))
.fill(Fill::Block(Block::new( .fill(Fill::Block(Block::new(
BlockKind::Wood, BlockKind::Wood,
Rgb::new(55, 25, 8), Rgb::new(55, 25, 8),
))); )));
// Tower cylinder // Tower cylinder
let tower_floor_pos = wpos.with_z(land.get_alt_approx(wpos) as i32); let tower_floor_pos = wpos.with_z(land.get_alt_approx(wpos) as i32);
painter painter
.prim(Primitive::cylinder( .prim(Primitive::cylinder(
tower_floor_pos, tower_floor_pos,
tower_radius - 1.0, tower_radius - 1.0,
tower_height, tower_height,
)) ))
.fill(Fill::Block(Block::empty())); .fill(Fill::Block(Block::empty()));
// Tower top floor // Tower top floor
let top_floor_z = (land.get_alt_approx(wpos) + tower_height - 2.0) as i32; let top_floor_z = (land.get_alt_approx(wpos) + tower_height - 2.0) as i32;
let tower_top_floor_pos = wpos.with_z(top_floor_z); let tower_top_floor_pos = wpos.with_z(top_floor_z);
painter painter
.prim(Primitive::cylinder(tower_top_floor_pos, tower_radius, 1.0)) .prim(Primitive::cylinder(tower_top_floor_pos, tower_radius, 1.0))
.fill(Fill::Block(Block::new( .fill(Fill::Block(Block::new(
BlockKind::Wood, BlockKind::Wood,
Rgb::new(55, 25, 8), Rgb::new(55, 25, 8),
))); )));
// Tower roof poles // Tower roof poles
let roof_pole_height = 5; let roof_pole_height = 5;
let relative_pole_positions = [ let relative_pole_positions = [
Vec2::new(-4, -4), Vec2::new(-4, -4),
Vec2::new(-4, 3), Vec2::new(-4, 3),
Vec2::new(3, -4), Vec2::new(3, -4),
Vec2::new(3, 3), Vec2::new(3, 3),
]; ];
relative_pole_positions relative_pole_positions
.iter() .iter()
.map(|rpos| wpos + rpos) .map(|rpos| wpos + rpos)
.for_each(|pole_pos| { .for_each(|pole_pos| {
painter painter
.line( .line(
pole_pos.with_z(top_floor_z), pole_pos.with_z(top_floor_z),
pole_pos.with_z(top_floor_z + roof_pole_height), pole_pos.with_z(top_floor_z + roof_pole_height),
1., 1.,
) )
.fill(Fill::Block(Block::new( .fill(Fill::Block(Block::new(
BlockKind::Wood, BlockKind::Wood,
Rgb::new(55, 25, 8), Rgb::new(55, 25, 8),
))); )));
}); });
// Tower roof // Tower roof
let roof_sphere_radius = 10; let roof_sphere_radius = 10;
let roof_radius = tower_radius + 1.0; let roof_radius = tower_radius + 1.0;
let roof_height = 3; let roof_height = 3;
let roof_cyl = painter.prim(Primitive::cylinder( let roof_cyl = painter.prim(Primitive::cylinder(
wpos.with_z(top_floor_z + roof_pole_height), wpos.with_z(top_floor_z + roof_pole_height),
roof_radius, roof_radius,
roof_height as f32, roof_height as f32,
)); ));
painter painter
.prim(Primitive::sphere( .prim(Primitive::sphere(
wpos.with_z( wpos.with_z(top_floor_z + roof_pole_height + roof_height - roof_sphere_radius),
top_floor_z + roof_pole_height + roof_height - roof_sphere_radius, roof_sphere_radius as f32,
), ))
roof_sphere_radius as f32, .intersect(roof_cyl)
)) .fill(Fill::Block(Block::new(
.intersect(roof_cyl) BlockKind::Wood,
.fill(Fill::Block(Block::new( Rgb::new(55, 25, 8),
BlockKind::Wood, )));
Rgb::new(55, 25, 8), });
)));
});
self.structure_locations self.structure_locations
.iter() .iter()