2013-03-13 96 views
1

我试图在我的画布游戏中实现像素完美碰撞检测,但是我似乎无法从我的精灵中获取像素信息。从画布精灵获取图像像素数据

我需要精灵的每个像素的x和y值,并且从我读过的内容中我使用getImageData()方法来做到这一点。

然而,这不起作用:

this.sprite = new Image(); 
this.sprite.src = 'img/player.png'; 
console.log(this.sprite.getImageData()); 

我是否可能使用了错误类型的精灵?因为我在控制台收到此错误:

Uncaught TypeError: Object # has no method 'getImageData'

+0

'getImageData()'是一种用于画布的方法,而不是图像。 “从我的精灵中获取像素信息”是什么意思? – romainberger 2013-03-13 20:03:25

+0

框检测并不困难 - 基于像素形状的检测可能会非常耗费流程。 请参阅:http://stackoverflow.com/questions/8017541/javascript-canvas-collision-detection和:http://stackoverflow.com/questions/4871669/collision-detection-in-javascript-game – 2013-03-13 20:08:39

+0

啊,我认为它可能是。我的意思是我想知道画布上x和y坐标的每个像素在我的精灵中。 @Diodeus,没有你想象的那么多。虽然它可以带有很多对象,但我一次只能在画布上放置几个精灵。此外,由于精灵不是矩形,因此盒检测对于此目的不够好。 – 2013-03-13 20:11:05

回答

5

下面介绍如何使用精灵的像素数据通常做完美的像素命中测试

首先,画你的精灵你看到画布上。

enter image description here

的隐藏画布创建精灵的红蒙面副本。此副本与精灵的尺寸完全相同,但仅包含透明或红色像素。

enter image description here

轨道可见精灵的边界框。单击边界框时,计算与精灵边界框(不涉及画布)相关的鼠标单击的X/Y。

然后,请参考红色遮罩的sprite,看看该X/Y处的对应像素是红色还是透明的。如果像素为红色,则您的像素完美匹配。如果像素是透明的,则没有命中。

在此图中,假设蓝色点是X/Y点击位置。由于红色遮罩画布中相应的X/Y像素为“红色”,因此这是一个HIT。

enter image description here

下面是代码来创建一个红掩盖精灵。我没有在这里显示命中测试的代码,但是如果您尝试并且无法编写命中测试代码,我也会花时间对代码测试进行编码。

重要提示:要使此代码运行,您必须避免跨域安全限制。确保您的图片源位于您的本地域,否则您将遇到跨域安全违规,并且屏蔽图像将不会被绘制...因此,您无法为您的精灵源执行此操作:http://otherDomain.com/picture.jpg

<!doctype html> 
<html> 
<head> 
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css --> 
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script> 

<style> 
    body{ background-color: ivory; padding:10px; } 
    canvas{border:1px solid blue;} 
</style> 

<script> 
    $(function(){ 

     var c=document.getElementById("canvas"); 
     var ctx=c.getContext("2d"); 

     var img=new Image(); 
     img.onload=function(){ 
      ctx.drawImage(this,100,25); 

      // make a red-masked copy of just the sprite 
      // on a separate canvas 
      var canvasCopy=document.getElementById("canvasCopy"); 
      var ctxCopy=canvasCopy.getContext("2d"); 
      canvasCopy.width=this.width; 
      canvasCopy.height=this.height; 
      ctxCopy.drawImage(img,0,0); 

      // make a red-masked copy of the sprite on a separate canvas 
      var imgData=ctxCopy.getImageData(0,0,c.width,c.height); 
      for (var i=0;i<imgData.data.length;i+=4) 
      { 
       if(imgData.data[i+3]>0){ 
        imgData.data[i]=255; 
        imgData.data[i+1]=0; 
        imgData.data[i+2]=0; 
        imgData.data[i+3]=255; 
       } 
      } 
      ctxCopy.putImageData(imgData,0,0);   

     } 
     img.src = "houseIcon.png"; 

    }); // end $(function(){}); 
</script> 

</head> 

<body> 
    <p>Original sprite drawn on canvas at XY:100/25</p> 
    <canvas id="canvas" width="400" height="300"></canvas> 
    <p>Red-masked on canvas used for hit-testing</p> 
    <canvas id="canvasCopy" width="300" height="300"></canvas> 

</body> 
</html> 

要做到2个精灵之间的像素完美的碰撞测试中,你会:

创建两个精灵#1和#精灵2红蒙面画布。

首先测试2个精灵的边界框是否碰撞。如果边界框没有碰撞,那么2个精灵不会相互碰撞,所以你可以在这里停止命中测试。

如果2个精灵是可能使用边界框测试进行碰撞,请为碰撞测试创建第三个画布。

您将使用画布的合成方法通过在第三个画布上绘制精灵#1和精灵#2来测试精灵#1和精灵#2之间的碰撞。使用合成,只有2个精灵的像素将被绘制在第三个画布上。

以下是如何与“目标输入”合成的工作原理:现有画布内容保留在新形状(sprite#2)和现有形状(sprite#1)内容重叠的位置。其他一切都是透明的。

所以......

绘制精灵#在变换状态下的进入第三画布1 (转换可能是移动,旋转,缩放,倾斜 - 什么!)。

将globalCompositeOperation设置为destination-in。

context.globalCompositeOperation = 'destination-over'; 

绘制子画面#2 在其转化的状态到第三画布。

此拉伸之后,第三画布包含只的子画面#1和子画面#2

测试在第三画布非透明像素的每个像素的碰撞部。如果您发现任何不透明的像素,则2个精灵将进行COLLIDING。

根据您想要在碰撞时采取什么动作,您可能只是在找到第一个碰撞像素时才纾困。

+0

哇。 [15个字符] – 11684 2013-04-07 12:57:04

+0

谢谢你的回答@markE。但是有一个问题,如果我们要使用'目标进入',为什么我们需要红色掩盖精灵?不重叠的像素不会被绘制,然后我们继续搜索不透明的像素。 – Airwavezx 2017-09-14 21:21:53