changed corredor generation to avoid placing corredors under rooms

This commit is contained in:
grimsace
2026-03-20 10:52:44 -05:00
parent 1eeb37894f
commit 57d14ba07a
2 changed files with 50 additions and 19 deletions
+30 -3
View File
@@ -52,6 +52,26 @@ pub struct DungeonLayout {
pub doors: Vec<Door>, pub doors: Vec<Door>,
} }
// Collect all room cells except those belonging to excluded room ids.
pub fn blocked_room_cells(rooms: &[Room], excluded_room_ids: &[usize]) -> HashSet<(usize, usize)> {
let excluded: HashSet<usize> = excluded_room_ids.iter().copied().collect();
let mut blocked = HashSet::new();
for (room_idx, room) in rooms.iter().enumerate() {
if excluded.contains(&room_idx) {
continue;
}
for x in room.x..(room.x + room.width) {
for y in room.y..(room.y + room.height) {
blocked.insert((x, y));
}
}
}
blocked
}
// Build a layout based on settings and a derived deterministic seed. // Build a layout based on settings and a derived deterministic seed.
pub fn generate_layout( pub fn generate_layout(
cols: usize, cols: usize,
@@ -178,9 +198,10 @@ pub fn generate_layout(
for (start_room_id, end_room_id) in room_edges { for (start_room_id, end_room_id) in room_edges {
let start = centers[start_room_id]; let start = centers[start_room_id];
let end = centers[end_room_id]; let end = centers[end_room_id];
let blocked = blocked_room_cells(&rooms, &[start_room_id, end_room_id]);
let path = if randomness <= 0.001 { let path = if randomness <= 0.001 {
shortest_path_cells(start, end, cols, rows, &HashSet::new()) shortest_path_cells(start, end, cols, rows, &blocked)
} else { } else {
Some(noisy_path( Some(noisy_path(
start, start,
@@ -188,10 +209,11 @@ pub fn generate_layout(
cols, cols,
rows, rows,
randomness, randomness,
&blocked,
&mut path_rng, &mut path_rng,
)) ))
} }
.or_else(|| shortest_path_cells(start, end, cols, rows, &HashSet::new())); .or_else(|| shortest_path_cells(start, end, cols, rows, &blocked));
if let Some(path) = path if let Some(path) = path
&& path.len() >= 2 && path.len() >= 2
@@ -656,6 +678,7 @@ fn noisy_path(
cols: usize, cols: usize,
rows: usize, rows: usize,
randomness: f32, randomness: f32,
blocked: &HashSet<(usize, usize)>,
rng: &mut SimpleRng, rng: &mut SimpleRng,
) -> Vec<(usize, usize)> { ) -> Vec<(usize, usize)> {
if start == end { if start == end {
@@ -698,6 +721,10 @@ fn noisy_path(
let mut best_score = f32::INFINITY; let mut best_score = f32::INFINITY;
for &candidate in &neighbors { for &candidate in &neighbors {
if blocked.contains(&candidate) && candidate != end {
continue;
}
let step_dir = ( let step_dir = (
candidate.0 as isize - current.0 as isize, candidate.0 as isize - current.0 as isize,
candidate.1 as isize - current.1 as isize, candidate.1 as isize - current.1 as isize,
@@ -734,7 +761,7 @@ fn noisy_path(
} }
if current != end if current != end
&& let Some(tail) = shortest_path_cells(current, end, cols, rows, &HashSet::new()) && let Some(tail) = shortest_path_cells(current, end, cols, rows, blocked)
{ {
for &cell in tail.iter().skip(1) { for &cell in tail.iter().skip(1) {
path.push(cell); path.push(cell);
+20 -16
View File
@@ -10,7 +10,9 @@ use std::thread;
use eframe::egui; use eframe::egui;
use egui::{Color32, Stroke}; use egui::{Color32, Stroke};
use layout::{DoorSettings, DungeonLayout, corridor_cells, shortest_path_cells}; use layout::{
DoorSettings, DungeonLayout, blocked_room_cells, corridor_cells, shortest_path_cells,
};
use ui::{AddTool, UiSettings, draw_side_panel}; use ui::{AddTool, UiSettings, draw_side_panel};
// Boot the native app and start the egui event loop. // Boot the native app and start the egui event loop.
@@ -333,7 +335,6 @@ impl DungeonApp {
// Recalculate corridor paths connected to a moved room. // Recalculate corridor paths connected to a moved room.
fn reroute_corridors_for_room(&mut self, room_idx: usize) { fn reroute_corridors_for_room(&mut self, room_idx: usize) {
let empty = HashSet::new();
for corridor in &mut self.layout.corridors { for corridor in &mut self.layout.corridors {
if corridor.start_room_id != room_idx && corridor.end_room_id != room_idx { if corridor.start_room_id != room_idx && corridor.end_room_id != room_idx {
continue; continue;
@@ -341,9 +342,15 @@ impl DungeonApp {
let start = self.layout.rooms[corridor.start_room_id].center_cell(); let start = self.layout.rooms[corridor.start_room_id].center_cell();
let end = self.layout.rooms[corridor.end_room_id].center_cell(); let end = self.layout.rooms[corridor.end_room_id].center_cell();
corridor.path = let blocked = blocked_room_cells(
shortest_path_cells(start, end, self.settings.cols, self.settings.rows, &empty) &self.layout.rooms,
.unwrap_or_else(|| vec![start, end]); &[corridor.start_room_id, corridor.end_room_id],
);
if let Some(path) =
shortest_path_cells(start, end, self.settings.cols, self.settings.rows, &blocked)
{
corridor.path = path;
}
} }
} }
@@ -383,6 +390,7 @@ impl DungeonApp {
self.drag_state = None; self.drag_state = None;
return; return;
} }
let corridor = &self.layout.corridors[drag.corridor_index];
let target = ( let target = (
(grid_x.floor().max(0.0) as usize).min(self.settings.cols.saturating_sub(1)), (grid_x.floor().max(0.0) as usize).min(self.settings.cols.saturating_sub(1)),
@@ -395,6 +403,10 @@ impl DungeonApp {
target, target,
self.settings.cols, self.settings.cols,
self.settings.rows, self.settings.rows,
&blocked_room_cells(
&self.layout.rooms,
&[corridor.start_room_id, corridor.end_room_id],
),
) else { ) else {
return; return;
}; };
@@ -540,16 +552,7 @@ impl DungeonApp {
return; return;
}; };
let mut blocked = HashSet::new(); let blocked = blocked_room_cells(&self.layout.rooms, &[start_room, end_room]);
for room in &self.layout.rooms {
for x in room.x..(room.x + room.width) {
for y in room.y..(room.y + room.height) {
blocked.insert((x, y));
}
}
}
blocked.remove(&start);
blocked.remove(&end);
let Some(path) = let Some(path) =
shortest_path_cells(start, end, self.settings.cols, self.settings.rows, &blocked) shortest_path_cells(start, end, self.settings.cols, self.settings.rows, &blocked)
@@ -1604,13 +1607,14 @@ fn reroute_path_through_cell(
target_cell: (usize, usize), target_cell: (usize, usize),
cols: usize, cols: usize,
rows: usize, rows: usize,
blocked_room_cells_set: &HashSet<(usize, usize)>,
) -> Option<Vec<(usize, usize)>> { ) -> Option<Vec<(usize, usize)>> {
let (&start, &end) = (original_path.first()?, original_path.last()?); let (&start, &end) = (original_path.first()?, original_path.last()?);
if start == end { if start == end {
return None; return None;
} }
let mut blocked = HashSet::new(); let mut blocked = blocked_room_cells_set.clone();
blocked.insert(original_cell); blocked.insert(original_cell);
blocked.remove(&start); blocked.remove(&start);
blocked.remove(&end); blocked.remove(&end);