You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在HTML5 Canvas中实现任意形状的碰撞检测?

HTML5 Canvas 游戏碰撞检测实用方案

矩形与矩形碰撞检测

这是游戏开发中最常用的基础检测,适合用矩形包围盒简化角色/物体的碰撞判断。

  • 核心逻辑:判断两个矩形的边界是否存在重叠,需同时满足以下4个条件:
    1. A的右边界 > B的左边界
    2. A的左边界 < B的右边界
    3. A的下边界 > B的上边界
    4. A的上边界 < B的下边界
  • 代码实现:
function rectRectCollision(rectA, rectB) {
  return (
    rectA.x + rectA.width > rectB.x &&
    rectA.x < rectB.x + rectB.width &&
    rectA.y + rectA.height > rectB.y &&
    rectA.y < rectB.y + rectB.height
  );
}

圆形与圆形碰撞检测

适用于圆形角色、子弹或场景元素,通过圆心距离与半径的关系判断。

  • 核心逻辑:计算两个圆心的距离平方(避免开方运算提升性能),若小于等于两半径之和的平方则碰撞
  • 代码实现:
function circleCircleCollision(circleA, circleB) {
  const dx = circleB.x - circleA.x;
  const dy = circleB.y - circleA.y;
  const distanceSquared = dx * dx + dy * dy;
  const radiusSum = circleA.radius + circleB.radius;
  return distanceSquared <= radiusSum * radiusSum;
}

矩形与圆形碰撞检测

常见组合(比如矩形角色+圆形障碍),通过找到矩形上离圆心最近的点来判断。

  • 核心逻辑:计算矩形上距离圆形圆心最近的点,再判断该点到圆心的距离是否小于等于圆的半径
  • 代码实现:
function rectCircleCollision(rect, circle) {
  // 找到矩形上离圆心最近的点
  const closestX = Math.max(rect.x, Math.min(circle.x, rect.x + rect.width));
  const closestY = Math.max(rect.y, Math.min(circle.y, rect.y + rect.height));
  
  const dx = circle.x - closestX;
  const dy = circle.y - closestY;
  return dx * dx + dy * dy <= circle.radius * circle.radius;
}

多边形与多边形碰撞检测(分离轴定理SAT)

针对不规则凸多边形的通用检测方案,是2D碰撞检测的核心算法之一。

  • 核心原理:如果能找到一条轴,使得两个多边形在该轴上的投影不重叠,则两者不碰撞;反之则碰撞
  • 代码实现(凸多边形适用):
// 计算多边形在指定轴上的投影范围
function getProjection(polygon, axis) {
  let min = dotProduct(polygon[0], axis);
  let max = min;
  for (let i = 1; i < polygon.length; i++) {
    const dot = dotProduct(polygon[i], axis);
    min = Math.min(min, dot);
    max = Math.max(max, dot);
  }
  return { min, max };
}

// 计算向量点积
function dotProduct(v1, v2) {
  return v1.x * v2.x + v1.y * v2.y;
}

// 检查两个投影是否重叠
function projectionsOverlap(p1, p2) {
  return p1.max >= p2.min && p2.max >= p1.min;
}

// 多边形碰撞检测主函数
function polygonPolygonCollision(polyA, polyB) {
  // 遍历第一个多边形的所有边,生成检测轴
  for (let i = 0; i < polyA.length; i++) {
    const p1 = polyA[i];
    const p2 = polyA[(i + 1) % polyA.length];
    // 生成边的垂直法线轴并归一化
    const axis = { x: p2.y - p1.y, y: p1.x - p2.x };
    const length = Math.sqrt(axis.x * axis.x + axis.y * axis.y);
    axis.x /= length;
    axis.y /= length;
    
    const projA = getProjection(polyA, axis);
    const projB = getProjection(polyB, axis);
    if (!projectionsOverlap(projA, projB)) return false;
  }

  // 遍历第二个多边形的所有边,生成检测轴
  for (let i = 0; i < polyB.length; i++) {
    const p1 = polyB[i];
    const p2 = polyB[(i + 1) % polyB.length];
    const axis = { x: p2.y - p1.y, y: p1.x - p2.x };
    const length = Math.sqrt(axis.x * axis.x + axis.y * axis.y);
    axis.x /= length;
    axis.y /= length;
    
    const projA = getProjection(polyA, axis);
    const projB = getProjection(polyB, axis);
    if (!projectionsOverlap(projA, projB)) return false;
  }

  return true;
}

性能优化技巧

  • 先做粗略检测:用矩形包围盒快速过滤掉明显不碰撞的对象,再进行精细检测
  • 空间划分:对大量对象使用网格、四叉树等方式分组,减少每帧需要检测的对象数量
  • 针对性检测:只对移动中的对象或处于同一区域的对象进行碰撞判断,避免全量遍历

内容的提问来源于stack exchange,提问作者Md Nazmul Islam

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 22:15:38