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 ;
1516use std:: sync:: { Arc , RwLock } ;
1617
1718use 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
155162impl 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
180196impl 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