当前位置:首页 > 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
  );
}

检测圆形碰撞

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

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)

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

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。这些引擎提供了完整的碰撞检测和物理模拟功能。

js实现碰撞

// 使用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
分享给朋友:

相关文章

js 进度条的实现

js 进度条的实现

使用 HTML 和 CSS 创建基础进度条 HTML 结构可以简单使用一个 div 元素作为容器,内部嵌套另一个 div 表示进度: <div class="progress-containe…

jquery.js

jquery.js

jQuery 是一个快速、简洁的 JavaScript 库,简化了 HTML 文档遍历、事件处理、动画设计和 Ajax 交互等操作。以下是关于 jQuery.js 的核心信息和使用方法: 获…

vue实现js休眠

vue实现js休眠

实现 JavaScript 休眠的方法 在 Vue 中实现 JavaScript 休眠(延迟执行)可以通过以下方式实现。由于 JavaScript 本身没有内置的 sleep 函数,通常使用 Prom…

js实现滑动

js实现滑动

实现滑动效果的方法 在JavaScript中实现滑动效果可以通过多种方式完成,以下是几种常见的实现方法: 使用CSS过渡和JavaScript触发 通过CSS定义过渡效果,JavaScript控制触…

js实现轮播代码

js实现轮播代码

基础轮播实现 使用HTML、CSS和JavaScript创建一个简单的轮播效果。HTML部分定义轮播容器和图片元素。 <div class="carousel"> <div c…

js 实现图片 放大

js 实现图片 放大

使用 CSS transform 实现图片放大 通过 CSS 的 transform: scale() 属性可以实现图片的平滑放大效果。结合 JavaScript 监听鼠标事件控制放大状态: con…