2010-04-30 97 views
8

我想检查HTML5画布中两个Sprites之间的碰撞。所以为了讨论的缘故,我们假设这两个精灵都是IMG对象,碰撞意味着alpha通道不是0.现在这两个精灵都可以围绕对象的中心旋转,但是没有其他变换,以防止这样做任何更容易。HTML5画布中的像素完美碰撞检测

现在显而易见的解决方案,我想出了会是这样:

  • 计算变换矩阵两种
  • 揣摩出的代码应该测试(如偏移两者的面积粗略估算+计算用于旋转的额外空间)
  • 对于相交矩形中的所有像素,变换坐标并在alpha通道的计算位置(舍入到最近的邻居)测试图像。然后在第一次击中时放弃。

我看到的问题是,a)JavaScript中没有矩阵类,这意味着我必须在JavaScript中这样做,这可能会很慢,我必须测试碰撞的每一帧,这使得这漂亮昂贵。此外,我必须复制一些我在绘图时必须做的事情(或者画布为我设置矩阵)。

我在想这里是否缺少任何东西,以及是否有更简单的碰撞检测解决方案。

+0

我无法找到答案,我问这个问题太:( – super 2013-12-26 14:27:38

回答

6

我不是一个JavaScript代码编写人员,但我想象同样的优化技巧对于JavaScript来说也同样适用于C++。

只需旋转精灵的角落而不是每个像素。实际上你会做类似软件纹理映射的事情。您可以使用各种梯度信息计算给定像素的x,y位置。查看软件纹理映射以获取更多信息。

如果四叉树将精灵分解为“命中”和“非命中”区域,则可以有效检查给定的四叉树分解是否全部为“未命中”,“全部命中”或“可能命中“(即包含点击和非点击像素,前两个点是微不足道的,在最后一个例子中,您将进入下一个分解点并重复测试,这样您只需检查您需要的像素, “无创”和“打”的大片,你不必做这么复杂的检查。

反正那只是一对夫妇的想法。

7

我要复制我的东西已经 必须在绘制

那么做,你可以做一个新的渲染环境,情节一个旋转的白色背景面膜时,设定合成操作lighter和在给定偏置曲线之上彼此旋转的面具。

现在,如果还有一个非白色的像素,就会有一个命中。你仍然需要getImageData,并通过像素筛选找出。通过向下缩放合成图像(依靠抗锯齿将某些像素保持为非白色),您可能会稍微减少一些工作量,但我认为它可能仍然会很慢。

我必须测试碰撞每个帧,这使得这非常昂贵。

是的,我认为你会使用预先计算的碰撞表。如果你有足够的空间,你可以为精灵a,精灵b,相对旋转,相对x归一化到旋转和相对y归一化到旋转的每个组合存储一个命中/不命中位。根据你有多少个精灵以及多少个旋转或移动步骤,这可能会变得相当大。

一个妥协方法是将每个精灵的预先旋转的掩码存储在一个JavaScript数组中(数字,给你32位/像素的容易&&可用数据,或者作为一个字符在Sring中,给你16位)和&&每行相交的精灵蒙版一起。或者,放弃像素,开始看例如。路径。

2

同样的问题,一种替代解决方案。首先,我使用getImageData数据来查找围绕精灵的多边形。这里要小心,因为该实现适用于具有透明背景且具有单个实体对象的图像。像一艘船。下一步是Ramer Douglas Peucker Algorithm以减少多边形中顶点的数量。我最终得到了一个很少顶点的多边形,它很容易便宜地旋转,并检查每个精灵与其他多边形的碰撞。

http://jsfiddle.net/rnrlabs/9dxSg/

var canvas = document.getElementById("canvas"); 
var context = canvas.getContext("2d"); 
var img = document.getElementById("img"); 

context.drawImage(img, 0,0); 
var dat = context.getImageData(0,0,img.width, img.height); 
// see jsfiddle 
var startPixel = findStartPixel(dat, 0); 
var path = followPath(startPixel, dat, 0); 
// 4 is RDP epsilon 
map1 = properRDP(path.map, 4, path.startpixel.x, path.startpixel.y); 

// draw 

context.beginPath(); 
context.moveTo(path.startpixel.x, path.startpixel.x); 
for(var i = 0; i < map.length; i++) { 
    var p = map[i]; 
    context.lineTo(p.x, p.y); 
} 
context.strokeStyle = 'red'; 
context.closePath(); 
context.stroke();