@@ -66,7 +66,7 @@ use bevy_ecs::{
6666 prelude:: * ,
6767 system:: SystemParam ,
6868} ;
69- use bevy_math:: { CompassOctant , Dir2 , Vec2 } ;
69+ use bevy_math:: { CompassOctant , Dir2 , Rect , Vec2 } ;
7070use bevy_ui:: { ComputedNode , UiGlobalTransform , UiSystems } ;
7171use thiserror:: Error ;
7272
@@ -576,7 +576,6 @@ fn score_candidate(
576576 // Get direction in mathematical coordinates, then flip Y for UI coordinates
577577 let dir = Dir2 :: from ( octant) . as_vec2 ( ) * Vec2 :: new ( 1.0 , -1.0 ) ;
578578 let to_candidate = candidate_pos - origin_pos;
579- let distance = to_candidate. length ( ) ;
580579
581580 // Check direction first
582581 // Convert UI coordinates (Y+ = down) to mathematical coordinates (Y+ = up) by flipping Y
@@ -599,15 +598,27 @@ fn score_candidate(
599598 return f32:: INFINITY ;
600599 }
601600
601+ // Calculate distance between rectangle edges, not centers
602+ let origin_rect = Rect :: from_center_size ( origin_pos, origin_size) ;
603+ let candidate_rect = Rect :: from_center_size ( candidate_pos, candidate_size) ;
604+ let dx = ( candidate_rect. min . x - origin_rect. max . x )
605+ . max ( origin_rect. min . x - candidate_rect. max . x )
606+ . max ( 0.0 ) ;
607+ let dy = ( candidate_rect. min . y - origin_rect. max . y )
608+ . max ( origin_rect. min . y - candidate_rect. max . y )
609+ . max ( 0.0 ) ;
610+ let distance = ( dx * dx + dy * dy) . sqrt ( ) ;
611+
602612 // Check max distance
603613 if let Some ( max_dist) = config. max_search_distance {
604614 if distance > max_dist {
605615 return f32:: INFINITY ;
606616 }
607617 }
608618
609- // Calculate alignment score
610- let alignment = if distance > 0.0 {
619+ // Calculate alignment score using center-to-center direction
620+ let center_distance = to_candidate. length ( ) ;
621+ let alignment = if center_distance > 0.0 {
611622 to_candidate. normalize ( ) . dot ( dir) . max ( 0.0 )
612623 } else {
613624 1.0
@@ -1171,4 +1182,42 @@ mod tests {
11711182 Some ( node_c)
11721183 ) ;
11731184 }
1185+
1186+ #[ test]
1187+ fn test_edge_distance_vs_center_distance ( ) {
1188+ let mut nav_map = DirectionalNavigationMap :: default ( ) ;
1189+ let config = AutoNavigationConfig :: default ( ) ;
1190+
1191+ let left = Entity :: from_bits ( 1 ) ;
1192+ let wide_top = Entity :: from_bits ( 2 ) ;
1193+ let bottom = Entity :: from_bits ( 3 ) ;
1194+
1195+ let left_node = FocusableArea {
1196+ entity : left,
1197+ position : Vec2 :: new ( 100.0 , 200.0 ) ,
1198+ size : Vec2 :: new ( 100.0 , 100.0 ) ,
1199+ } ;
1200+
1201+ let wide_top_node = FocusableArea {
1202+ entity : wide_top,
1203+ position : Vec2 :: new ( 350.0 , 150.0 ) ,
1204+ size : Vec2 :: new ( 300.0 , 80.0 ) ,
1205+ } ;
1206+
1207+ let bottom_node = FocusableArea {
1208+ entity : bottom,
1209+ position : Vec2 :: new ( 270.0 , 300.0 ) ,
1210+ size : Vec2 :: new ( 100.0 , 80.0 ) ,
1211+ } ;
1212+
1213+ let nodes = vec ! [ left_node, wide_top_node, bottom_node] ;
1214+
1215+ auto_generate_navigation_edges ( & mut nav_map, & nodes, & config) ;
1216+
1217+ assert_eq ! (
1218+ nav_map. get_neighbor( left, CompassOctant :: East ) ,
1219+ Some ( wide_top) ,
1220+ "Should navigate to wide_top not bottom, even though bottom's center is closer."
1221+ ) ;
1222+ }
11741223}
0 commit comments