1

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

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

但是,这不起作用:

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

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

未捕获的类型错误:对象 # 没有方法 'getImageData'

4

1 回答 1

5

以下是如何使用精灵的像素数据进行像素完美的命中测试

首先,在可见的画布上正常绘制精灵。

在此处输入图像描述

在隐藏的画布上创建精灵的红色蒙版副本。此副本与精灵的大小完全相同,但包含透明或红色像素。

在此处输入图像描述

跟踪可见精灵的边界框。单击边界框时,计算鼠标点击相对于精灵边界框的 X/Y (与画布无关)。

然后,参考红色蒙版精灵,查看 X/Y 处对应的像素是红色还是透明。如果像素是红色的,那么您就有了一个像素完美的命中。如果像素是透明的,则没有命中。

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

在此处输入图像描述

这是创建红色蒙面精灵的代码。我没有在这里展示命中测试的代码,但如果你尝试编写命中测试但无法编写命中测试代码,我也会花时间编写命中测试代码。

重要提示:要运行此代码,您必须避免跨域安全限制。确保您的图像源在您的本地域上,否则您将遇到跨域安全违规并且不会绘制掩蔽图像......所以您不能为您的精灵源执行此操作:http: //otherDomain.com/图片.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 个精灵之间进行像素完美的碰撞测试,您可以:

为 sprite#1 和 sprite#2 创建一个红色蒙版画布。

首先测试 2 个精灵的边界框是否发生碰撞。如果边界框没有碰撞,则 2 个精灵没有碰撞,因此您可以在此处停止命中测试。

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

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

以下是使用“destination-in”合成的工作原理:现有画布内容保留在新形状 (sprite#2) 和现有形状 (sprite#1) 内容重叠的位置。其他一切都变得透明。

所以……</p>

将sprite#1的变换状态绘制到第三个画布中(变换可以是移动、旋转、缩放、倾斜——任何东西!)。

将 globalCompositeOperation 设置为destination-in。

context.globalCompositeOperation = 'destination-over';

将sprite#2的变换状态绘制到第三个画布中。

在此绘制之后,第三个画布仅包含 sprite#1 和 sprite#2 的碰撞部分

测试第三个画布中的每个像素的不透明像素。如果您发现任何不透明的像素,则 2 个精灵正在碰撞。

根据您在碰撞时要采取的操作,您可能会在找到第一个碰撞像素时退出。

于 2013-03-13T21:37:46.033 回答