圆形与矩形的Swept AABB碰撞检测误判问题求助
问题分析与解决方案
你的问题出在两个核心地方:矩形膨胀方式错误,以及Swept AABB的时间计算未考虑运动方向,导致边角误判。
错误原因
矩形膨胀逻辑错误
你提到“将矩形的x、y方向范围扩大2倍圆形半径”,但正确的圆-矩形碰撞转换应该是将原矩形的每个边界向外偏移1倍圆半径,而非整体扩大2倍。如果只是单纯增加矩形宽高而不调整起始坐标,会导致膨胀后的矩形位置偏移,把离原矩形边角超过半径的区域也纳入碰撞检测范围,从而产生误判。运动方向未处理导致时间计算颠倒
原代码中直接计算进入/退出时间,但没有根据速度方向交换时间顺序。当点向矩形内部反向移动时,原本的进入时间会变成退出时间,反之亦然,导致时间区间计算错误,误判路径与矩形相交。
修正后的实现
第一步:正确膨胀矩形
假设圆半径为r,原矩形参数为rectx, recty, rectw, recth,膨胀后的矩形参数应调整为:
const r = 你的圆半径; const expandedRectX = rectx - r; // 左边界左移r const expandedRectY = recty - r; // 上边界上移r const expandedRectW = rectw + 2*r; // 宽度增加2r(左右各扩r) const expandedRectH = recth + 2*r; // 高度增加2r(上下各扩r)
第二步:修正Swept AABB函数
function sweptAABB(pointX, pointY, velX, velY, deltaTime, rectX, rectY, rectW, rectH) { // 计算当前帧内点的总位移 const moveX = velX * deltaTime; const moveY = velY * deltaTime; // 矩形的边界 const rectLeft = rectX; const rectRight = rectX + rectW; const rectTop = rectY; const rectBottom = rectY + rectH; // 计算x方向的进入/退出时间 let tEnterX, tExitX; if (moveX === 0) { // x方向无移动,判断是否已在矩形内 tEnterX = (pointX >= rectLeft && pointX <= rectRight) ? -Infinity : Infinity; tExitX = (pointX >= rectLeft && pointX <= rectRight) ? Infinity : -Infinity; } else { tEnterX = (rectLeft - pointX) / moveX; tExitX = (rectRight - pointX) / moveX; // 速度为负时,进入/退出时间颠倒,交换两者 if (moveX < 0) [tEnterX, tExitX] = [tExitX, tEnterX]; } // 计算y方向的进入/退出时间 let tEnterY, tExitY; if (moveY === 0) { // y方向无移动,判断是否已在矩形内 tEnterY = (pointY >= rectTop && pointY <= rectBottom) ? -Infinity : Infinity; tExitY = (pointY >= rectTop && pointY <= rectBottom) ? Infinity : -Infinity; } else { tEnterY = (rectTop - pointY) / moveY; tExitY = (rectBottom - pointY) / moveY; // 速度为负时,交换进入/退出时间 if (moveY < 0) [tEnterY, tExitY] = [tExitY, tEnterY]; } // 整体进入时间是两个方向的最晚进入时间,退出时间是两个方向的最早退出时间 const enterTime = Math.max(tEnterX, tEnterY); const exitTime = Math.min(tExitX, tExitY); // 碰撞判定:路径与矩形有交集,且交集在当前帧时间范围内(0到1) return enterTime <= exitTime && exitTime >= 0 && enterTime <= 1; }
原理说明
Swept AABB的核心是计算点(圆心)在当前帧内的运动路径与膨胀矩形的时间交集:
enterTime:点完全进入矩形的最早时间(0=帧开始,1=帧结束)exitTime:点完全离开矩形的最晚时间- 当
enterTime <= exitTime时,说明路径与矩形有交集;同时确保交集落在当前帧范围内(exitTime >=0且enterTime <=1),即可判定碰撞。
内容的提问来源于stack exchange,提问作者Blue Artifact




