繁体   English   中英

HTML5 Canvas中的像素完美碰撞检测

[英]Pixel Perfect Collision Detection in HTML5 Canvas

我想检查HTML5画布中两个Sprite之间的碰撞。 因此,为了讨论,让我们假设两个精灵都是IMG对象,并且碰撞意味着alpha通道不是0.现在这两个精灵都可以围绕对象的中心旋转,但是如果这样做则没有其他变换更容易。

现在,我想出的明显解决方案是:

  • 计算两者的变换矩阵
  • 找出代码应该测试的区域的粗略估计(比如两者的偏移+计算的旋转额外空间)
  • 对于交叉矩形中的所有像素,转换坐标并在Alpha通道的计算位置(舍入到最近邻居)处测试图像。 然后在第一次击中时中止。

我看到的问题是:a)JavaScript中没有矩阵类,这意味着我必须在JavaScript中这样做,这可能非常慢,我必须测试每帧的冲突,这使得它非常昂贵。 此外,我必须复制我在绘图时必须做的事情(或者画布对我来说,设置矩阵)。

我想知道我在这里是否遗漏了什么,以及是否有更容易的碰撞检测解决方案。

我不是一个javascript编码器,但我认为相同的优化技巧对于Javascript和C ++一样有效。

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

如果您将四元组分解为“命中”和“非命中”区域,那么您可以有效地检查给定的四元树分解是否全部为“未命中”,“全部命中”或“可能命中”(即包含命中和非命中像素。前两个是很容易通过的。在最后一种情况下,你可以进入下一个分解级别并重复测试。这样你只需检查你需要的像素和大面积的“非击中“和”命中“你不必做这么复杂的检查。

无论如何这只是一些想法。

我必须复制我在绘图时必须做的事情

好吧,您可以创建一个新的渲染上下文,将一个旋转的白色背景遮罩绘制到它上面,将合成操作设置为lighter亮,并将给定偏移处的另一个旋转遮罩绘制在顶部。

现在,如果剩下非白色像素,则会有一个点击。 你仍然需要getImageData并筛选像素才能找到它。 您可以通过向下缩放结果图像来减少该工作量(依靠抗锯齿来保持一些像素非白色),但我认为它可能仍然会很慢。

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

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

一个折衷是存储每个子画面的一个JavaScript阵列中的旋转的前面罩(数目,给你32个比特/容易像素&& -able数据,或如在SRING一个字符,给你16位)和&&交叉精灵的每一行掩盖在一起。

或者,放弃像素并开始查看例如。 路径。

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

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();

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM