Canvas碰撞检测统一用画布坐标系:矩形用AABB判断轴向重叠,圆形用圆心距平方与半径和平方比较;AABB不依赖DOM,抗transform/滚动/iframe干扰,核心是检测X或Y轴是否分离。

Canvas碰撞检测不依赖DOM坐标,关键在于统一用画布坐标系做数学判断。矩形用AABB算法比边界是否重叠,圆形用圆心距离平方和半径和平方比较——这两个方法轻量、稳定、无兼容性问题。
矩形碰撞:用AABB判断重叠
AABB(轴对齐包围盒)是Canvas中最常用也最可靠的矩形碰撞方式。它直接使用对象在Canvas坐标系下的x、y、width、height属性,不依赖CSS或视口位置,不受transform、滚动、iframe影响。
- 核心逻辑是“找分离轴”:只要在X轴或Y轴上完全错开,就不碰撞
- 推荐写法(避免边界漏判):
function isRectCollision(a, b) { return !(a.x + a.width <= b.x || b.x + b.width <= a.x || a.y + a.height <= b.y || b.y + b.height <= a.y); } - 注意所有坐标必须同源——比如都来自
requestAnimationFrame中更新的位置,别混入getBoundingClientRect()返回的CSS像素值
圆形碰撞:用距离平方代替开方
两个圆是否相交,只取决于圆心距离是否小于半径之和。但实际计算中,Math.sqrt()既慢又有浮点误差,旧版Safari还不支持Math.hypot(),所以应手算距离平方。
- 标准实现:
function isCircleCollision(c1, c2) { const dx = c1.x - c2.x; const dy = c1.y - c2.y; const rSum = c1.radius + c2.radius; return dx * dx + dy * dy <= rSum * rSum; } - 可进一步优化:若对象半径固定,提前存好
rSumSq = (r1 + r2) ** 2,避免每次重复计算 - 确保
c1.x、c2.y等值都是Canvas画布内的绝对坐标,不是相对于某个容器的偏移量
常见陷阱与避坑要点
看似简单的碰撞逻辑,出错往往不在公式本身,而在坐标来源和执行时机。
- 别用
getBoundingClientRect()获取位置后直接参与计算——滚动、缩放、iframe都会导致偏移,校正成本高且易漏 - 动画中若用
transform: translate()移动元素,其DOM坐标已失真,Canvas内对象必须靠JS手动维护x/y - 多个对象频繁检测时,加一层空间分区(如网格划分),只比对可能靠近的几组,性能提升明显
- 贴边情况(如
a.x + a.width === b.x)属于“接触”,按需求决定是否视为碰撞;上述AABB写法已包含等号,能正确捕获
什么时候该换别的方法?
AABB和圆形检测覆盖80%以上场景,但有明确限制:
- 矩形旋转后不再轴对齐 → AABB失效,需用SAT(分离轴定理)或多边形投影
- 图形轮廓不规则(如手绘角色、地图区域)→ 考虑离屏Canvas+像素检测,但开销大,慎用
- 需要精确到边缘弧度或凹陷部位 → 得引入物理引擎或自定义多边形碰撞库

















