当前位置:首页 > JavaScript

js实现碰撞

2026-01-30 10:56:12JavaScript

检测矩形碰撞

使用矩形边界框检测碰撞是最简单的方法。假设两个矩形的位置和尺寸已知,可以通过比较它们的边界来判断是否重叠。

function checkRectCollision(rect1, rect2) {
  return (
    rect1.x < rect2.x + rect2.width &&
    rect1.x + rect1.width > rect2.x &&
    rect1.y < rect2.y + rect2.height &&
    rect1.y + rect1.height > rect2.y
  );
}

检测圆形碰撞

对于圆形物体,通过比较两圆圆心距离与半径之和来判断碰撞。

js实现碰撞

function checkCircleCollision(circle1, circle2) {
  const dx = circle1.x - circle2.x;
  const dy = circle1.y - circle2.y;
  const distance = Math.sqrt(dx * dx + dy * dy);
  return distance < circle1.radius + circle2.radius;
}

像素级碰撞检测

更精确的方法是使用像素级检测,适合不规则形状物体。HTML5 Canvas提供了getImageData方法可以获取像素数据。

function checkPixelCollision(ctx1, ctx2, x1, y1, x2, y2) {
  const data1 = ctx1.getImageData(x1, y1, width, height).data;
  const data2 = ctx2.getImageData(x2, y2, width, height).data;

  for (let i = 0; i < data1.length; i += 4) {
    if (data1[i+3] > 0 && data2[i+3] > 0) {
      return true;
    }
  }
  return false;
}

分离轴定理(SAT)

对于凸多边形之间的碰撞检测,分离轴定理是最可靠的方法。需要检查所有边的法向量作为潜在分离轴。

js实现碰撞

function projectPolygon(axis, polygon) {
  let min = Infinity;
  let max = -Infinity;

  for (const point of polygon.points) {
    const proj = point.x * axis.x + point.y * axis.y;
    min = Math.min(min, proj);
    max = Math.max(max, proj);
  }

  return {min, max};
}

function checkSATCollision(poly1, poly2) {
  const axes = [...poly1.edges, ...poly2.edges].map(edge => {
    return {x: -edge.y, y: edge.x}; // 法向量
  });

  for (const axis of axes) {
    const proj1 = projectPolygon(axis, poly1);
    const proj2 = projectPolygon(axis, poly2);

    if (proj1.max < proj2.min || proj2.max < proj1.min) {
      return false;
    }
  }
  return true;
}

性能优化建议

对于大量物体的碰撞检测,应使用空间分割技术如四叉树或网格来减少检测次数。四叉树将空间递归划分为四个区域,只检测同一区域或相邻区域内的物体。

class Quadtree {
  constructor(bounds, capacity) {
    this.bounds = bounds;
    this.capacity = capacity;
    this.objects = [];
    this.divided = false;
  }

  insert(obj) {
    if (!this.bounds.contains(obj)) return false;

    if (this.objects.length < this.capacity) {
      this.objects.push(obj);
      return true;
    }

    if (!this.divided) this.subdivide();

    return (this.northeast.insert(obj) || 
            this.northwest.insert(obj) ||
            this.southeast.insert(obj) || 
            this.southwest.insert(obj));
  }

  query(range, found) {
    if (!this.bounds.intersects(range)) return found;

    for (const obj of this.objects) {
      if (range.contains(obj)) found.push(obj);
    }

    if (this.divided) {
      this.northeast.query(range, found);
      this.northwest.query(range, found);
      this.southeast.query(range, found);
      this.southwest.query(range, found);
    }

    return found;
  }
}

物理引擎集成

对于复杂场景,建议使用成熟的物理引擎如Matter.js或Box2D。这些引擎提供了完整的碰撞检测和物理模拟功能。

// 使用Matter.js示例
const engine = Matter.Engine.create();
const boxA = Matter.Bodies.rectangle(400, 200, 80, 80);
const boxB = Matter.Bodies.rectangle(450, 50, 80, 80);
Matter.Composite.add(engine.world, [boxA, boxB]);

Matter.Events.on(engine, 'collisionStart', (event) => {
  const pairs = event.pairs;
  pairs.forEach(pair => {
    console.log('碰撞发生在:', pair.bodyA, pair.bodyB);
  });
});

标签: js
分享给朋友:

相关文章

vue.js实现轮播

vue.js实现轮播

Vue.js 实现轮播功能 使用第三方库(推荐) Vue.js 生态中有许多成熟的轮播组件库,例如 vue-awesome-swiper 或 swiper,它们功能丰富且易于集成。 安装 swipe…

js实现跳转

js实现跳转

使用 window.location 跳转 通过修改 window.location.href 实现页面跳转,这是最常用的方法。 window.location.href = 'https://…

js实现倒计时

js实现倒计时

使用 setInterval 实现倒计时 通过 setInterval 定时器每秒更新剩余时间,适用于简单倒计时场景。 function countdown(seconds, callback) {…

js实现预览

js实现预览

文件上传预览实现 使用JavaScript实现文件上传预览功能,可以通过FileReader对象读取文件内容并显示预览。以下代码支持图片、文本和PDF文件的预览: // HTML部分需要包含…

js画图实现

js画图实现

使用Canvas API绘制图形 Canvas是HTML5提供的绘图API,通过JavaScript操作Canvas元素可以绘制各种图形。以下是一个简单的示例: <canvas id="myC…

js实现吸色

js实现吸色

使用Canvas实现吸色功能 通过Canvas的getImageData方法获取像素颜色数据。创建一个Canvas元素,将目标图像绘制到Canvas上,通过鼠标事件获取坐标对应的颜色值。 c…