前回のあたり判定の計算を利用して、簡単なミニゲームを作ってみます。 複数のオブジェクトのあたり判定を計算するところがミソです。

サンプルを見る

複数の要素を同時に処理する。

今回のサンプルでは、赤い四角形を敵機、青い四角形を時機に見立てて、画面をクリックすると弾を発射し、弾が敵機に命中すると、敵機が消滅します。

その際に、敵機と弾それぞれであたり判定の計算をする必要があるのですが、前回のサンプルでは、単体のオブジェクト同士の判定しかしていませんでした。

そこで、今回は敵機と弾すべてであたり判定の計算をしなくてはいけないのですが、そのために丁度よいメソッドがjQueryには実装されています。

それが、「eachメソッドです。」

使い方は下記のとおりです。

$(セレクタ).each(function(index, element) {
    //index : 処理対象の番号
    //element : 処理対象のエレメント
});

今回のサンプルでは、敵機は「<div class="obj"></div>」としていますが、この敵機を一遍に処理しようとすると、

$(".obj").each(function(index, element) {
    var target = $(element);
    //後は、targetに対して処理を実行する。
});

こうすることで、「obj」というクラス名がついた要素すべてに対して処理を実行できます。

この仕組みを使えば、たとえ敵機が何機いようと、「obj」というクラス名をつけさえすれば数を意識することなく処理が行えます。

次に、弾の方の処理になりますが、こちらは敵機と違い、最初から数が決まっているわけではありません。 でも、こちらも敵機と同様に「eachメソッド」が利用できます。

どのように実装するかというと、今回のサンプルでは、「hit」というクラス名を付けて、appendしているのです。 当然といえば当然ですが、「eachメソッド」は後から画面に追加されたエレメントに対しても有効なのです。

では、全ソースを見てみましょう。

var FPS = 30;
var obj;
var jiki;

var EnterFrameID;

$(function(e) {
    obj = $(".obj");
    jiki = $("#jiki");

    EnterFrameID = setInterval(enterFrameTicker , 1000 / FPS);

    $(document).on("mousemove" , function(e)
    {
        jiki.css({left:e.clientX + "px"});
    });

    //---------------------------------画面をクリックすると敵機をappendします。 
    $(document).on("click" , function(e)
    {
        var target = $('<div class="hit"></div>');
        target.css({left:e.clientX + "px"});
        $("body").append(target);
    });
});

function enterFrameTicker()
{
    //---------------------------------appendされた弾すべてで処理を実行する。 
    $(".hit").each(function(index, element) {
        var hitObj = $(element);
        var hitObjY = parseFloat(hitObj.css("top").replace(/px/ , ""));
        hitObj.css({top:hitObjY - 10 + "px"});

        if(hitObjY < 0)
        {
            hitObj.remove();
        }
         //---------------------------------弾のeachメソッドの中で、敵機のあたり判定を 
         //---------------------------------ネストする。 
        obj.each(function(index, element) {
            var target = $(element);
            //あたり判定用の右下座標
            var L = parseFloat(target.css("left").replace(/px/ , ""));
            var R = L + target.width();
            var T = parseFloat(target.css("top").replace(/px/ , ""));
            var B = T + target.height();

            //青いボックスの4点座標を取得
            var hitX = parseFloat(hitObj.css("left").replace(/px/ , ""));
            var hitY = parseFloat(hitObj.css("top").replace(/px/ , ""));
            var hitRight = hitX + hitObj.width();
            var hitBottom = hitY + hitObj.height();

            if(target.css("display") == "none")
            {
                return;
            }

            //あたり判定の計算
            if(L < hitX && hitX < R && T < hitY && hitY < B)
            {
                target.css("display" , "none");
                target.remove();
                hitObj.remove();
            }
            else if(L < hitRight && hitRight < R && T < hitY && hitY < B    )
            {
                target.css("display" , "none");
                target.remove();
                hitObj.remove();
            }
            else if(L < hitX && hitX < R && T < hitBottom && hitBottom < B)
            {
                target.css("display" , "none");
                target.remove();
                hitObj.remove();
            }
            else if(L < hitRight && hitRight < R && T < hitBottom && hitBottom < B)
            {
                target.css("display" , "none");
                target.remove();
                hitObj.remove();
            }
        });
    });
}

ちょっとながいソースですが、ソース中に「//---------------------------------」でコメントしている部分がもっとも重要なところです。

よく見てみると、「eachメソッド」内で、引数で渡された「element」をjQueryオブジェクトにしている点以外は、前回の単体のオブジェクトの処理とほとんど変わりません。

このように、「eachメソッド」を使うことで、簡単に複数オブジェクトに対して、あたかも単体の処理のように記述できます。。 特に、ゲームなど、オブジェクトの数が決まっていないようなもので有効ですね!

河野 義貴
インハウスのFlashクリエイターとして勤務後、2010年独立。一年間のフリーランス期間を経て、2011年9月にスウィーツアンドストリーム株式会社を設立。主にFlash・HTML5を駆使した、PC・スマートフォン向けインタラクティブコンテンツを中心に活動中。マイナビクリエイターセミナーの講師としてもおなじみ。