二维碰撞检测

检测二维游戏中碰撞的算法取决于可以发生碰撞的形状类型(例如,矩形与矩形,矩形与圆形,圆形与圆形)。通常,您将有一个简单的通用形状来覆盖称为“命中框”的实体,即使碰撞不完全像素完美,它看起来也足够好,并且在多个实体之间具有性能。本文回顾了在二维游戏中提供碰撞检测的最常用技术。

轴对齐包围盒

碰撞检测的一种更简单的形式是在两个轴对齐的矩形之间,这意味着没有旋转。该算法通过确保两个矩形的 4 个边之间没有间隙来工作。任何间隙意味着不存在碰撞。

js
Crafty.init(200, 200);

const dim1 = { x: 5, y: 5, w: 50, h: 50 };
const dim2 = { x: 20, y: 10, w: 60, h: 40 };

const rect1 = Crafty.e("2D, Canvas, Color").attr(dim1).color("red");

const rect2 = Crafty.e("2D, Canvas, Color, Keyboard, Fourway")
  .fourway(2)
  .attr(dim2)
  .color("blue");

rect2.bind("EnterFrame", function () {
  if (
    rect1.x < rect2.x + rect2.w &&
    rect1.x + rect1.w > rect2.x &&
    rect1.y < rect2.y + rect2.h &&
    rect1.y + rect1.h > rect2.y
  ) {
    // Collision detected!
    this.color("green");
  } else {
    // No collision
    this.color("blue");
  }
});

圆形碰撞

碰撞检测的另一个简单形状是在两个圆形之间。该算法通过取两个圆形的中心点,并确保中心点之间的距离小于两个半径加在一起的距离来工作。

js
Crafty.init(200, 200);

const dim1 = { x: 5, y: 5 };
const dim2 = { x: 20, y: 20 };

Crafty.c("Circle", {
  circle(radius, color) {
    this.radius = radius;
    this.w = this.h = radius * 2;
    this.color = color || "#000000";

    this.bind("Move", Crafty.DrawManager.drawAll);
    return this;
  },

  draw() {
    const ctx = Crafty.canvas.context;
    ctx.save();
    ctx.fillStyle = this.color;
    ctx.beginPath();
    ctx.arc(
      this.x + this.radius,
      this.y + this.radius,
      this.radius,
      0,
      Math.PI * 2,
    );
    ctx.closePath();
    ctx.fill();
    ctx.restore();
  },
});

const circle1 = Crafty.e("2D, Canvas, Circle").attr(dim1).circle(15, "red");

const circle2 = Crafty.e("2D, Canvas, Circle, Fourway")
  .fourway(2)
  .attr(dim2)
  .circle(20, "blue");

circle2.bind("EnterFrame", function () {
  const dx = circle1.x - circle2.x;
  const dy = circle1.y - circle2.y;
  const distance = Math.sqrt(dx * dx + dy * dy);

  const colliding = distance < circle1.radius + circle2.radius;
  this.color = colliding ? "green" : "blue";
});

分离轴定理

这是一种碰撞算法,可以检测任何两个多边形之间的碰撞。它的实现比以上方法更复杂,但功能更强大。这种算法的复杂性意味着我们需要考虑性能优化,这将在下一节中介绍。

实现 SAT 超出了本页面的范围,因此请查看下面推荐的教程

  1. 分离轴定理 (SAT) 解释
  2. 碰撞检测和响应
  3. 使用分离轴定理进行碰撞检测
  4. SAT(分离轴定理)
  5. 分离轴定理

碰撞性能

虽然一些碰撞检测算法很简单,但测试每个实体与每个其他实体可能会浪费循环。通常游戏会将碰撞分为两个阶段,粗略阶段和精细阶段。

粗略阶段

粗略阶段应该为您提供一个可能发生碰撞的实体列表。这可以通过空间数据结构来实现,该数据结构将为您提供实体存在的粗略位置及其周围存在的实体。空间数据结构的一些例子包括四叉树、R 树或空间哈希表。

精细阶段

当您有一小部分实体要检查时,您将想要使用精细阶段算法(如上面列出的算法)来确定是否存在碰撞。