fix: four interlocking pathfinding bugs causing panic, failure, and yo-yo teleportation

1. CSV Overflow Panic: Use saturating_sub to prevent underflow when total_failed_paths > n
2. Heuristic Scale Mismatch: octile_distance_3d now divides by ITILE_SIZE to match g-score units
3. Goal Z Offset: Correct target.as_ivec3() - ivec3(0,0,1) not ITILE_SIZE (target already has +1.0)
4. Gravity Yo-Yo: Clear current_path and target when entity falls to prevent teleportation loop
This commit is contained in:
2026-03-18 17:49:07 +00:00
parent 00cbd92491
commit e9ef5ebbcd
2 changed files with 1908 additions and 6 deletions
+1900
View File
File diff suppressed because it is too large Load Diff
+8 -6
View File
@@ -183,8 +183,8 @@ pub fn prepare_paths(
continue;
};
let start = transform.translation.as_ivec3();
let goal = target.as_ivec3() - ivec3(0, 0, ITILE_SIZE);
let distance = octile_distance_3d(start, goal) / ITILE_SIZE;
let goal = target.as_ivec3() - ivec3(0, 0, 1);
let distance = octile_distance_3d(start, goal);
if distance <= PATHFINDER_SHORT_PATH_MAX_TILES {
let path = calculate_path_benchmarked(&tilemap, start, goal);
@@ -352,6 +352,8 @@ pub fn movement(mut query: Query<(&mut Ambulatory, &mut Transform)>, tilemap: Re
let current_pos = transform.translation;
if !is_standable_tile(&tilemap, current_pos.as_ivec3()) {
transform.translation.z -= TILE_SIZE;
ambulatory.current_path = None;
ambulatory.target = None;
return;
}
@@ -433,9 +435,9 @@ fn calculate_movement_cost(move_dir: IVec3) -> i32 {
}
fn octile_distance_3d(a: IVec3, b: IVec3) -> i32 {
let dx = (a.x - b.x).abs();
let dy = (a.y - b.y).abs();
let dz = (a.z - b.z).abs();
let dx = (a.x - b.x).abs() / ITILE_SIZE;
let dy = (a.y - b.y).abs() / ITILE_SIZE;
let dz = (a.z - b.z).abs() / ITILE_SIZE;
let (dmax, dmid, dmin) = sorted_desc(dx, dy, dz);
10 * dmax + 4 * dmid + dmin
}
@@ -767,7 +769,7 @@ fn write_benchmark_csv(bench: &PathfindingBenchmark, filename: &str) -> std::io:
let duration = bench.path_calc_times_us.get(i).copied().unwrap_or(0);
let length = bench.path_lengths.get(i).copied().unwrap_or(0);
let nodes = bench.nodes_expanded.get(i).copied().unwrap_or(0);
let success = i < (n - bench.total_failed_paths as usize);
let success = i < n.saturating_sub(bench.total_failed_paths as usize);
writeln!(file, "{},{},{},{},{}", i, duration, length, nodes, success)?;
}