路径寻路厚网格生成的边缘用例异常:适配大尺寸单元的A*实现问题
问题定位
你的实现存在流程缺陷,并非参考算法本身的固有问题。
偏差产生的核心原因
你当前的距离场计算逻辑,仅做了单方向、单趟的网格遍历:
- 遍历顺序是固定的从上到下、从左到右
- 这种逻辑只能把上方、左侧已经计算完成的邻居的距离值,传播到当前处理的单元格
- 根本无法接收下方、右侧邻居传播过来的距离值——因为遍历到当前单元格时,下方、右侧的位置还没被处理,保留的还是初始的大数值
- 对应你测试用例里出错的位置(倒数第二行的中间单元格):单趟遍历到这里时,它下方的相邻单元格还没完成计算,能拿到的最小邻居值只有上方位置传递来的偏大值,自然会输出错误的5,而非从下方边界传播上来应得到的3。
正确的计算流程
大体积单位寻路配套的厚度网格(距离场)生成方案,要求做双向两趟扫描,才能把全方向的最近墙体距离值完整传播到每个单元格:
- 第一趟扫描:从左上角出发,按从上到下、从左到右的顺序遍历,参考所有邻居的当前值计算单元格的距离
- 第二趟扫描:从右下角出发,按从下到上、从右到左的反向顺序遍历,重新计算单元格的距离,取计算过程中的更小值更新网格
你的getSmallestNeighbor函数本身逻辑没有问题,不需要修改。
代码修复调整
把原代码里单趟循环的部分,替换成双趟双向遍历的逻辑即可:
// 第一趟:左上->右下 正向遍历 for (let i = 0; i < width * height; i++) { if (outputGrid[i] > 0) { outputGrid[i] = getSmallestNeighbor(outputGrid, i, width, height) + 2; } } // 第二趟:右下->左上 反向遍历 for (let i = width * height - 1; i >= 0; i--) { if (outputGrid[i] > 0) { const neighborMin = getSmallestNeighbor(outputGrid, i, width, height); // 取当前值和新计算值的更小值,避免覆盖已得到的更小距离 outputGrid[i] = Math.min(outputGrid[i], neighborMin + 2); } }
修复后运行5×5全自由网格的测试,就会得到你预期的正确输出:
[1, 1, 1, 1, 1] [1, 3, 3, 3, 1] [1, 3, 5, 3, 1] [1, 3, 3, 3, 1] [1, 1, 1, 1, 1]
内容的提问来源于stack exchange,提问作者Ryan Peschel
相关产品推荐
相关产品推荐

