Skip to content

Commit 5cdee26

Browse files
author
Tim Willebrands
committed
Light only goes trough doors
1 parent 2d50529 commit 5cdee26

3 files changed

Lines changed: 563 additions & 113 deletions

File tree

src/collision.rs

Lines changed: 64 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
//! [`crate::engine::DEFAULT_ENGINE`]; new Rust callers should construct a
1313
//! [`crate::engine::LightingEngine`] and call methods on it.
1414
15+
use std::collections::HashSet;
1516
use std::sync::{Arc, RwLock};
1617

1718
use crate::engine::DEFAULT_ENGINE;
@@ -150,6 +151,12 @@ pub struct HybridCollisionMap {
150151
union_find: Arc<RwLock<UnionFind>>,
151152
pixel_map: PixelCollisionMap,
152153
map_size: usize,
154+
/// Canonical `(lo, hi)` cell-index pairs where the broad-phase walk is
155+
/// allowed to step between two cells that the union-find considers to be
156+
/// in different rooms. Populated by the engine from its `door_edges`
157+
/// overlay — a door dissolves the wall only along its own cell-edges, not
158+
/// across the entire room boundary (which is what a UF union would do).
159+
door_cell_edges: HashSet<(usize, usize)>,
153160
}
154161

155162
impl HybridCollisionMap {
@@ -159,29 +166,82 @@ impl HybridCollisionMap {
159166
union_find: Arc::new(RwLock::new(uf)),
160167
pixel_map: PixelCollisionMap::new(map_size as u16, map_size as u16),
161168
map_size,
169+
door_cell_edges: HashSet::new(),
162170
}
163171
}
164172

165173
pub fn update_map_data(&mut self, map_data: Vec<i32>, map_size: usize) {
166174
if let Ok(mut uf) = self.union_find.write() {
167175
*uf = UnionFind::new(map_data, map_size);
168176
}
177+
self.map_size = map_size;
169178
}
170179

171180
pub fn pixel_map_mut(&mut self) -> &mut PixelCollisionMap {
172181
&mut self.pixel_map
173182
}
174183

184+
/// Replace the set of open door cell-edges. Each entry is a canonical
185+
/// `(lo, hi)` cell-index pair flagging "the broad-phase walk may step
186+
/// across these two cells even though they are in different rooms".
187+
pub fn set_door_cell_edges(&mut self, edges: HashSet<(usize, usize)>) {
188+
self.door_cell_edges = edges;
189+
}
190+
175191
pub fn pixel_map(&self) -> &PixelCollisionMap {
176192
&self.pixel_map
177193
}
178194
}
179195

180196
impl CollisionDetector for HybridCollisionMap {
181197
fn is_blocked(&self, x0: i16, y0: i16, x1: i16, y1: i16) -> bool {
182-
if let Ok(mut uf) = self.union_find.write() {
183-
if !uf.cast_ray(x0 as i32, y0 as i32, x1 as i32, y1 as i32) {
184-
return true;
198+
let size = self.map_size as i32;
199+
let in_bounds = |x: i32, y: i32| x >= 0 && y >= 0 && x < size && y < size;
200+
let (x0i, y0i, x1i, y1i) = (x0 as i32, y0 as i32, x1 as i32, y1 as i32);
201+
202+
if in_bounds(x0i, y0i) && in_bounds(x1i, y1i) {
203+
if let Ok(mut uf) = self.union_find.write() {
204+
let dx = x1i - x0i;
205+
let dy = y1i - y0i;
206+
let nx = dx.abs();
207+
let ny = dy.abs();
208+
let sx = if dx > 0 { 1 } else { -1 };
209+
let sy = if dy > 0 { 1 } else { -1 };
210+
211+
let mut px = x0i;
212+
let mut py = y0i;
213+
let mut ix = 0;
214+
let mut iy = 0;
215+
let mut current_idx = (py * size + px) as usize;
216+
let mut current_room = uf.find(current_idx);
217+
218+
while ix < nx || iy < ny {
219+
let prev_idx = current_idx;
220+
if (ix as f32 + 0.5) / (nx as f32) < (iy as f32 + 0.5) / (ny as f32) {
221+
px += sx;
222+
ix += 1;
223+
} else {
224+
py += sy;
225+
iy += 1;
226+
}
227+
if !in_bounds(px, py) {
228+
return true;
229+
}
230+
let next_idx = (py * size + px) as usize;
231+
let next_room = uf.find(next_idx);
232+
if next_room != current_room {
233+
let pair = if prev_idx <= next_idx {
234+
(prev_idx, next_idx)
235+
} else {
236+
(next_idx, prev_idx)
237+
};
238+
if !self.door_cell_edges.contains(&pair) {
239+
return true;
240+
}
241+
}
242+
current_idx = next_idx;
243+
current_room = next_room;
244+
}
185245
}
186246
}
187247
self.pixel_map.is_blocked(x0, y0, x1, y1)
@@ -192,6 +252,7 @@ impl CollisionDetector for HybridCollisionMap {
192252
*uf = UnionFind::new(vec![0; self.map_size * self.map_size], self.map_size);
193253
}
194254
self.pixel_map.clear();
255+
self.door_cell_edges.clear();
195256
}
196257

197258
fn as_any(&self) -> &dyn std::any::Any {

0 commit comments

Comments
 (0)