欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

碰撞检测

程序员文章站 2022-03-13 12:33:41
...

引子

碰撞检测(Collision Detection)这个东西,之前找 canvas 相关资料的时候碰到过,有些好奇,就去尝试了解一下。

简介

与碰撞检测有些类似的一个概念:命中检测(Hit-testing),也被广泛运用。

在计算机图形编程中,命中检测是确定用户控制的光标(或触摸屏上的触摸点)是否与屏幕上绘制的给定图形对象(如形状)产生相交的过程。根据这个定义,web 开发中碰到鼠标点击下拉菜单等这些交互都属于这个范畴。

碰撞检测用于检测多个不同图形对象的交叉点,不是光标与一个或多个图像对象的交叉点。在 web 游戏中也涉及到这些,2D 游戏中的碰撞检测算法,依赖于碰撞物体的形状(例如矩形与矩形、矩形与圆形、圆形与圆形)。基于 canvas,下面看看几种简单的情景。

光标碰撞检测

使用 canvas 创建交互时,在画布内点击,如果需要判断点击所在的图形,就需要做碰撞检测。思路比较简单,就是要检测光标点击的坐标是否在某个形状里面。在测试中发现几点需要注意:

  • 遍历形状的顺序,因为绘制的图形可能重叠,后绘制的一般在上层,这个时候倒序遍历才合理。
  • 获取点击坐标时,注意移动端和 PC 端对应属性,移动端 touch 属性中可能有多个坐标。
  • 图形的形状,规则图形和非规则图形判断的方式有差异。

这是简单的示例,移动端访问如下:

碰撞检测

基于像素颜色碰撞检测

上面数学计算的方式,如果在一些图案信息较多的情况下,需要存储大量的数据,会非常的不方便。另外的一种方式就是取得像素块,检测它们的颜色。例如这个示例,移动端访问如下:

碰撞检测

示例中矩形区域是图片,其中线条颜色都是黑色,实现的思路是在小球移动之前,先取包含了小球且比小球稍大的空间像素,遍历像素数据,判断是否有黑色且不透明,如果有就说明在下一次重绘时就会发生碰撞。在迷宫类的游戏实现中,这种方式就会很方便,见小游戏 Maze

在测试中发现几点需要注意:

  • 选择图片时,需要注意图片中颜色的使用,因为要用来作为判断依据,色值不要随意混用。
  • 使用 getImageData 方法时,获取数据的位置是根据 canvas 实际的像素数据,而不是渲染显示的大小。

矩形与矩形碰撞检测

这里是指轴对齐(意味着没有旋转)的两个矩形碰撞检测。下面的一个算法可以用来进行判断:

var rect1 = {x: 5, y: 5, width: 50, height: 50}
var rect2 = {x: 20, y: 10, width: 10, height: 10}

if (rect1.x <= rect2.x + rect2.width &&
   rect1.x + rect1.width >= rect2.x &&
   rect1.y <= rect2.y + rect2.height &&
   rect1.height + rect1.y >= rect2.y) {
    // collision detected!
}

上面的条件,以刚好碰撞的状态做对照,思考起来会比较方便理解。这是简单的示例,移动端访问如下:

碰撞检测

圆形与圆形碰撞检测

这种形式的碰撞检测,通过两个圆心之间的直线距离,与两个圆的半径之和作比较。

var circle1 = {radius: 20, x: 5, y: 5};
var circle2 = {radius: 12, x: 10, y: 5};

var dx = circle1.x - circle2.x;
var dy = circle1.y - circle2.y;
var distance = Math.sqrt(dx * dx + dy * dy);

if (distance <= circle1.radius + circle2.radius) {
    // collision detected!
}

这是简单示例,移动端访问如下:

碰撞检测

从上面的示例中,发现如果使用在动态的场景下,效果并不一定如预期。

参考资料