feat: courtyard layout generation for BSP 2
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
5a565844dd
commit
2fb4042fba
2 changed files with 151 additions and 5 deletions
|
|
@ -6,6 +6,7 @@ extern crate alloc;
|
|||
use pxl8d::*;
|
||||
use pxl8d::chunk::ChunkId;
|
||||
use pxl8d::chunk::stream::ClientChunkState;
|
||||
use pxl8d::procgen::LayoutMode;
|
||||
|
||||
const TICK_RATE: u64 = 30;
|
||||
const TICK_NS: u64 = 1_000_000_000 / TICK_RATE;
|
||||
|
|
@ -126,9 +127,8 @@ pub extern "C" fn main(_argc: i32, _argv: *const *const u8) -> i32 {
|
|||
width: 20,
|
||||
height: 20,
|
||||
seed: 12345u32.wrapping_add(2),
|
||||
min_room_size: 14,
|
||||
max_room_size: 16,
|
||||
num_rooms: 1,
|
||||
layout: LayoutMode::Courtyard,
|
||||
..ProcgenParams::default()
|
||||
}),
|
||||
_ => None,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -19,6 +19,12 @@ pub struct LightSource {
|
|||
pub radius: f32,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq)]
|
||||
pub enum LayoutMode {
|
||||
Dungeon,
|
||||
Courtyard,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct ProcgenParams {
|
||||
pub width: i32,
|
||||
|
|
@ -27,6 +33,7 @@ pub struct ProcgenParams {
|
|||
pub min_room_size: i32,
|
||||
pub max_room_size: i32,
|
||||
pub num_rooms: i32,
|
||||
pub layout: LayoutMode,
|
||||
}
|
||||
|
||||
impl Default for ProcgenParams {
|
||||
|
|
@ -38,6 +45,7 @@ impl Default for ProcgenParams {
|
|||
min_room_size: 3,
|
||||
max_room_size: 6,
|
||||
num_rooms: 8,
|
||||
layout: LayoutMode::Dungeon,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1074,6 +1082,144 @@ pub fn generate_rooms(params: &ProcgenParams) -> Bsp {
|
|||
bsp.into()
|
||||
}
|
||||
|
||||
pub fn generate(params: &ProcgenParams) -> Bsp {
|
||||
generate_rooms(params)
|
||||
pub fn generate_courtyard(params: &ProcgenParams) -> Bsp {
|
||||
let mut rng = Rng::new(params.seed);
|
||||
let mut grid = RoomGrid::new(params.width, params.height);
|
||||
grid.fill(1);
|
||||
|
||||
let mut rooms: Vec<Bounds> = Vec::new();
|
||||
|
||||
let cx = params.width / 2;
|
||||
let cy = params.height / 2;
|
||||
let court_half = 4;
|
||||
let court_x = cx - court_half;
|
||||
let court_y = cy - court_half;
|
||||
let court_w = court_half * 2;
|
||||
let court_h = court_half * 2;
|
||||
|
||||
for ry in court_y..(court_y + court_h) {
|
||||
for rx in court_x..(court_x + court_w) {
|
||||
grid.set(rx, ry, 0);
|
||||
}
|
||||
}
|
||||
rooms.push(Bounds { x: court_x, y: court_y, w: court_w, h: court_h });
|
||||
|
||||
let wing_dirs: [(i32, i32); 4] = [(0, -1), (0, 1), (-1, 0), (1, 0)];
|
||||
|
||||
for &(dx, dy) in &wing_dirs {
|
||||
let room_w = 3 + (rng.next() % 3) as i32;
|
||||
let room_h = 3 + (rng.next() % 3) as i32;
|
||||
|
||||
let (rx, ry) = if dx != 0 {
|
||||
let rx = if dx > 0 { court_x + court_w + 2 } else { court_x - room_w - 2 };
|
||||
let ry = cy - room_h / 2;
|
||||
(rx, ry)
|
||||
} else {
|
||||
let rx = cx - room_w / 2;
|
||||
let ry = if dy > 0 { court_y + court_h + 2 } else { court_y - room_h - 2 };
|
||||
(rx, ry)
|
||||
};
|
||||
|
||||
let rx = rx.max(1).min(params.width - room_w - 1);
|
||||
let ry = ry.max(1).min(params.height - room_h - 1);
|
||||
|
||||
for y in ry..(ry + room_h) {
|
||||
for x in rx..(rx + room_w) {
|
||||
grid.set(x, y, 0);
|
||||
}
|
||||
}
|
||||
|
||||
let room_cx = rx + room_w / 2;
|
||||
let room_cy = ry + room_h / 2;
|
||||
if dx != 0 {
|
||||
carve_corridor_h(&mut grid, cx, room_cx, room_cy);
|
||||
} else {
|
||||
carve_corridor_v(&mut grid, cy, room_cy, room_cx);
|
||||
}
|
||||
|
||||
let primary = Bounds { x: rx, y: ry, w: room_w, h: room_h };
|
||||
rooms.push(primary);
|
||||
|
||||
let extra_count = 1 + (rng.next() % 2) as i32;
|
||||
for _ in 0..extra_count {
|
||||
let ew = 2 + (rng.next() % 3) as i32;
|
||||
let eh = 2 + (rng.next() % 3) as i32;
|
||||
|
||||
let (ex, ey) = if dx != 0 {
|
||||
let ex = if dx > 0 { rx + room_w + 1 } else { rx - ew - 1 };
|
||||
let ey = ry + (rng.next() % room_h.max(1) as u32) as i32 - eh / 2;
|
||||
(ex, ey)
|
||||
} else {
|
||||
let ex = rx + (rng.next() % room_w.max(1) as u32) as i32 - ew / 2;
|
||||
let ey = if dy > 0 { ry + room_h + 1 } else { ry - eh - 1 };
|
||||
(ex, ey)
|
||||
};
|
||||
|
||||
let ex = ex.max(1).min(params.width - ew - 1);
|
||||
let ey = ey.max(1).min(params.height - eh - 1);
|
||||
|
||||
for y in ey..(ey + eh) {
|
||||
for x in ex..(ex + ew) {
|
||||
grid.set(x, y, 0);
|
||||
}
|
||||
}
|
||||
|
||||
let ecx = ex + ew / 2;
|
||||
let ecy = ey + eh / 2;
|
||||
if rng.next() % 2 == 0 {
|
||||
carve_corridor_h(&mut grid, room_cx, ecx, room_cy);
|
||||
carve_corridor_v(&mut grid, room_cy, ecy, ecx);
|
||||
} else {
|
||||
carve_corridor_v(&mut grid, room_cy, ecy, room_cx);
|
||||
carve_corridor_h(&mut grid, room_cx, ecx, ecy);
|
||||
}
|
||||
|
||||
rooms.push(Bounds { x: ex, y: ey, w: ew, h: eh });
|
||||
}
|
||||
}
|
||||
|
||||
let mut bsp = BspBuilder::new();
|
||||
grid_to_bsp(&mut bsp, &grid);
|
||||
|
||||
let light_height = 80.0;
|
||||
let fireball_pos = Vec3::new(384.0, light_height, 324.0);
|
||||
let fireball_exclusion_radius = 150.0;
|
||||
|
||||
let lights: Vec<LightSource> = rooms.iter().filter_map(|room| {
|
||||
let room_cx = (room.x as f32 + room.w as f32 / 2.0) * CELL_SIZE;
|
||||
let room_cz = (room.y as f32 + room.h as f32 / 2.0) * CELL_SIZE;
|
||||
|
||||
let ddx = room_cx - fireball_pos.x;
|
||||
let ddz = room_cz - fireball_pos.z;
|
||||
if ddx * ddx + ddz * ddz < fireball_exclusion_radius * fireball_exclusion_radius {
|
||||
return None;
|
||||
}
|
||||
|
||||
let intensity = if room.w >= 6 && room.h >= 6 { 2.0 } else { 1.5 };
|
||||
let radius = if room.w >= 6 && room.h >= 6 { 250.0 } else { 160.0 };
|
||||
|
||||
Some(LightSource {
|
||||
position: Vec3::new(room_cx, light_height, room_cz),
|
||||
intensity,
|
||||
radius,
|
||||
})
|
||||
}).collect();
|
||||
|
||||
let mut lights = lights;
|
||||
lights.push(LightSource {
|
||||
position: Vec3::new(860.0, light_height, 416.0),
|
||||
intensity: 1.2,
|
||||
radius: 120.0,
|
||||
});
|
||||
|
||||
compute_bsp_vertex_lighting(&mut bsp, &lights);
|
||||
|
||||
bsp.into()
|
||||
}
|
||||
|
||||
pub fn generate(params: &ProcgenParams) -> Bsp {
|
||||
match params.layout {
|
||||
LayoutMode::Dungeon => generate_rooms(params),
|
||||
LayoutMode::Courtyard => generate_courtyard(params),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue