fix(pathfinding): correct BinaryHeap ordering and movement threshold

- Fix PathNode and ChunkPathNode Ord impl to use correct min-heap ordering
  (self.f_score.cmp vs other.f_score.cmp) - was causing zig-zag paths
- Fix movement threshold formula to use tile_weight directly
  (walk_speed * tile_weight / 50) instead of inverted multiplier
- Update comments to reflect 'higher = slower to traverse' semantics
This commit is contained in:
2026-03-19 20:27:36 +00:00
parent c4890fa23e
commit a97e2908ed
+9 -12
View File
@@ -155,10 +155,9 @@ struct PathNode {
impl Ord for PathNode { impl Ord for PathNode {
fn cmp(&self, other: &Self) -> std::cmp::Ordering { fn cmp(&self, other: &Self) -> std::cmp::Ordering {
other self.f_score
.f_score .cmp(&other.f_score)
.cmp(&self.f_score) .then_with(|| self.g_score.cmp(&other.g_score))
.then_with(|| other.g_score.cmp(&self.g_score))
} }
} }
@@ -508,8 +507,7 @@ pub fn movement(mut query: Query<(&mut Ambulatory, &mut Transform)>, tilemap: Re
if ambulatory.walk_speed > 0. { if ambulatory.walk_speed > 0. {
let tile_weight = get_tile_weight(&tilemap, current_pos.as_ivec3()); let tile_weight = get_tile_weight(&tilemap, current_pos.as_ivec3());
let speed_multiplier = (tile_weight as f32) / 50.0; let threshold = (ambulatory.walk_speed as i32 * tile_weight as i32 / 50) as u32;
let threshold = (ambulatory.walk_speed * speed_multiplier) as u32;
if ambulatory.step_recovery <= threshold { if ambulatory.step_recovery <= threshold {
ambulatory.step_recovery += 1; ambulatory.step_recovery += 1;
@@ -557,7 +555,7 @@ fn is_standable_tile(tilemap: &TileMap, pos: IVec3) -> bool {
tilemap.is_standable(pos) tilemap.is_standable(pos)
} }
/// Get the A* weight for a tile position. Lower is better (faster to traverse). /// Get the A* weight for a tile position. Higher = slower to traverse.
/// Returns 100 (default) if tile not found. /// Returns 100 (default) if tile not found.
#[inline] #[inline]
fn get_tile_weight(tilemap: &TileMap, pos: IVec3) -> u8 { fn get_tile_weight(tilemap: &TileMap, pos: IVec3) -> u8 {
@@ -566,7 +564,7 @@ fn get_tile_weight(tilemap: &TileMap, pos: IVec3) -> u8 {
/// Calculate movement cost including tile weight. /// Calculate movement cost including tile weight.
/// Base costs: cardinal=10, diagonal=14, vertical~50. /// Base costs: cardinal=10, diagonal=14, vertical~50.
/// Tile weight adds: (weight - 50) / 5 to make heavier tiles more costly. /// Tile weight adds: (weight - 50) / 5 to make higher-weight tiles more costly.
fn calculate_movement_cost(move_dir: IVec3, tile_weight: u8) -> i32 { fn calculate_movement_cost(move_dir: IVec3, tile_weight: u8) -> i32 {
let base_cost = match ( let base_cost = match (
move_dir.x.abs() / ITILE_SIZE, move_dir.x.abs() / ITILE_SIZE,
@@ -851,10 +849,9 @@ impl PartialEq for ChunkPathNode {
impl Ord for ChunkPathNode { impl Ord for ChunkPathNode {
fn cmp(&self, other: &Self) -> std::cmp::Ordering { fn cmp(&self, other: &Self) -> std::cmp::Ordering {
other self.f_score
.f_score .cmp(&other.f_score)
.cmp(&self.f_score) .then_with(|| self.g_score.cmp(&other.g_score))
.then_with(|| other.g_score.cmp(&self.g_score))
} }
} }