HTML5动画如何实现碰撞检测_HTML5物理碰撞逻辑【碰撞指南】

判断两个元素内物体是否碰撞需用JavaScript手动计算几何关系:矩形用AABB检测,圆形用距离公式,混合形状先AABB后精确检测;禁用getBoundingClientRect()和isPointInPath()等不可靠方法,须维护物体数学表示并参与时间步长。

怎么判断两个 元素里的物体是否碰撞了

HTML5 本身不提供“碰撞检测”功能,所有逻辑都得靠 JavaScript 手动计算。真正起作用的是你在 requestAnimationFrame 循环里持续更新的物体位置(xywidthheightradius),再用几何公式比对——不是靠 DOM 元素或 CSS 属性自动触发。

常见错误是试图监听 collision 事件,或者给 oncollision 属性,这在标准 HTML 中根本不存在。

  • 矩形碰撞:检查两个 rect 的边界是否重叠(轴对齐包围盒,AABB)
  • 圆形碰撞:用两点间距离公式,比较 distance
  • 混合形状(如圆+矩形):通常先用 AABB 快速排除,再做更精确的点-圆或边-圆检测

ctx.isPointInPath() 能不能用来做碰撞检测

不能直接用于物体间碰撞,它只回答“某个坐标点是否落在当前路径内”。你得手动把一个物体的边缘采样成多个点,再逐个调用 isPointInPath() 去测另一个物体——性能差、精度低、逻辑绕。

更实际的做法是:自己维护每个物体的数学表示(比如 {x: 100, y: 150, radius: 20}),用纯数值运算判断,完全绕过渲染上下文。

示例:两个圆碰撞判断

function circlesCollide(a, b) {
  const dx = a.x - b.x;
  const dy = a.y - b.y;
  const distance = Math.sqrt(dx * dx + dy * dy);
  return distance <= a.radius + b.radius;
}

getBoundingClientRect() 检测 DOM 元素碰撞靠谱吗

仅适用于静态、非旋转、非缩放的 或其他块级元素,且必须确保它们都在同一坐标系(无 transform: translateZ()iframe 嵌套、position: fixed 等干扰)。一旦有 canvas 绘制内容、CSS 动画、或使用 transform 移动,getBoundingClientRect() 返回的位置就和实际图形位置脱节。

典型陷阱:

  • transform: rotate(30deg) 旋转一个方块后,它的包围盒变大了,但 getBoundingClientRect() 返回的是旋转后的外接矩形,不是原始形状
  • canvas 内绘制的图形,getBoundingClientRect() 只返回整个 标签的位置,无法获取内部像素级轮廓
  • 滚动页面时,若没用 pageX/pageY 校正,坐标会错位

物理引擎要不要引入,比如 Matter.js 或 p2.js

如果你要做带质量、摩擦、弹性、关节、多边形分解的真实物理交互,引入轻量引擎是合理选择;但若只是“小球碰到墙反弹”或“方块走到一起就变色”,手写几十行 AABB + 速度反射就够了。

性能和体积差异明显:

  • Matter.js 压缩后约 180KB,启动开销高,调试链路长
  • 纯 JS 碰撞逻辑可控制在 1KB 内,所有状态可见、可断点、可单步
  • 引擎默认假设你用它的 BodyWorld,和你已有的 canvas 渲染循环容易耦合过深

建议先实现最简版本,等出现以下情况再考虑升级:需要连续碰撞(tunneling)、旋转体精确碰撞、或频繁添加/销毁动态刚体。

最容易被忽略的一点:无论手写还是用引擎,**时间步长(delta time)必须参与速度计算**。固定帧率(如 60fps)下用 dx = vx 还能凑合,但只要动画卡顿或设备性能波动,没乘 delta 就会漂移、穿透、反弹失真。