1

キャンバス ゲームにピクセル パーフェクトな衝突検出を実装しようとしていますが、スプライトからピクセル情報を取得できないようです。

スプライトの各ピクセルの x 値と y 値が必要です。私が読んだことから、getImageData()メソッドを使用してそれを行います。

ただし、これは機能しません。

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

間違ったタイプのスプライトを使用している可能性がありますか? コンソールに次のエラーが表示されるためです。

キャッチされていない TypeError: オブジェクト # にはメソッド '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 つのスプライト間でピクセル単位の衝突テストを行うには、次のようにします。

スプライト #1 とスプライト #2 の両方に赤いマスクのキャンバスを作成します。

まず、2 つのスプライトのバウンディング ボックスが衝突しているかどうかをテストします。バウンディング ボックスが衝突していない場合は、2 つのスプライトが衝突していないため、ここでヒット テストを停止できます。

バウンディング ボックス テストを使用して 2 つのスプライトが衝突している可能性がある場合は、衝突テスト用に 3 つ目のキャンバスを作成します。

キャンバスの合成方法を使用して、スプライト #1 とスプライト #2 の両方を 3 番目のキャンバスに描画することにより、スプライト #1 とスプライト #2 の間の衝突をテストします。合成を使用すると、2 つのスプライトのCOLLIDINGピクセルのみが 3 番目のキャンバスに描画されます。

「destination-in」で合成する方法は次のとおりです。 既存のキャンバス コンテンツは、新しいシェイプ (スプライト #2) と既存のシェイプ (スプライト #1) の両方のコンテンツが重なる場所に保持されます。それ以外はすべて透明になります。

だから…</p>

スプライト #1を変換された状態で 3 番目のキャンバスに描画します (変換は、移動、回転、拡大縮小、傾斜など何でも可能です!)。

globalCompositeOperation を destination-in に設定します。

context.globalCompositeOperation = 'destination-over';

変形された状態のスプライト #2を3 番目のキャンバスに描画します。

この描画の後、3 番目のキャンバスにはスプライト #1 とスプライト #2 の衝突部分のみが含まれます。

3 番目のキャンバスの各ピクセルで、透明でないピクセルをテストします。透明でないピクセルが見つかった場合、2 つのスプライトは衝突しています。

衝突時にどのようなアクションを実行したいかによっては、最初に衝突するピクセルを見つけたときに脱出することもできます。

于 2013-03-13T21:37:46.033 に答える