第5回 アクションゲームを作ってみよう(ぬりかべ) – jQuery入門

2009 年 5 月 1 日 投稿者: naga3

jQuery入門第5回は、JavaScriptでアクションゲームを作ってみます。jQueryはゲームに向いた作りでは無いので、ちょっと無理矢理なところがあると思いますがご勘弁を。
作るゲームはもちろん超大作MMOです。MMOとは(M)丸いのが(M)モリモリ(O)大きくなるゲームの略です。まずは遊べるゲーム画面をどうぞ。

ぬりかべ

自分自身や壁にぶつからないように、なるべく沢山の壁を塗ってください。マウスをクリックすると曲がります。

ぬりかべのソース

前回よりも少し長めですが、きっと大丈夫。
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html lang="ja">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<script type="text/javascript" src="http://www.google.com/jsapi"></script>
<script type="text/javascript">google.load("jquery", "1.3.2");</script>

<script type="text/javascript">
var FLEN = 16;                        // フィールドの大きさ
var px = 0, py = 1;                // プレイヤー座標
var vx = 1, vy = 0;                // プレイヤー速度
var intid;                                // setInterval用ID
var score = 0;                        // 得点

$(function() {$('#start').click(init);});

// 初期化
function init() {
    // フィールドを表示する。
    var field = '';
    for (var y = 0; y < FLEN; y++) {
        for (var x = 0; x < FLEN; x++) {
            field += '<span id="field_' + x + '_' + y + '">';
            if (x == 0 || x == FLEN - 1 || y == 0 || y == FLEN - 1) field += '■';
            else field += '□';
            field += '</span>';
        }
        field += '<br />';
    }
    $('#field').html(field);

    // 100ms毎にmainLoop関数が走る。
    intid = setInterval(mainLoop, 100);

    // マウス押下時に移動方向を時計回りに90度動かす。
    $().mousedown(function() {
        if (vx == 1) {vx = 0; vy = 1;}
        else if (vy == 1) {vx = -1; vy = 0;}
        else if (vx == -1) {vx = 0; vy = -1;}
        else if (vy == -1) {vx = 1; vy = 0;}
        return false;
    })

    // マウス移動時の選択を無効にする。
    $().mousemove(function() {return false});
}

// メインループ
function mainLoop() {
    var over = false;

    // 移動と当たり判定
    px += vx; py += vy;
    var item = $('#field_' + px + '_' + py);
    if (item.html() != '□') over = true;
    item.html('●');

    // ゲームオーバー処理
    if (over) {
        alert('ゲームオーバー\nとくてん:' + score);
        clearInterval(intid);
    }

    score++;
}
</script>
</head>
<body>
<div id="field" style="line-height: 1em"><a id="start" href="#">ゲーム開始</a></table>
</body>
</html>

プログラムの解説

ドキュメントが準備されたときに呼び出される処理

$(function() {$('#start').click(init);});
<div id="field" style="line-height: 1em"><a id="start" href="#">ゲーム開始</a></table>
ブラウザにHTMLが読み込まれて準備ができたときに、「ゲーム開始」リンクをクリックするとinit関数を呼び出すように設定しています。

init関数

init関数には、最初に一度だけ実行される、初期化処理が書かれています。
for (var y = 0; y < FLEN; y++) {
    for (var x = 0; x < FLEN; x++) {
        field += '<span id="field_' + x + '_' + y + '">';
        if (x == 0 || x == FLEN - 1 || y == 0 || y == FLEN - 1) field += '■';
        else field += '□';
        field += '</span>';
    }
    field += '<br />';
}
$('#field').html(field);
この部分で、idがfieldのdiv内にフィールド画面のHTMLを書いています。HTMLを要素内に流し込む方法には、appendメソッドを使って少しずつ要素を入れて行く方法もありますが、要素の挿入は遅いので、今回は文字列でHTMLを組み立てて、最後のhtmlメソッドで一気にdiv内に流し込んでいます。
このHTMLで重要な部分は、フィールドの要素(壁・空白)ひとつひとつをspanタグで包み、idとしてそれぞれのx,y座標を入れている点です。これによってプレイヤーが移動したときに簡単にその場所が壁であるか空白であるかが判断できるのです。
intid = setInterval(mainLoop, 100);
100ミリ秒ごとにmainLoop関数を呼び出しています。setIntervalは第2引数で指定した間隔で第1引数の関数を呼び出すJavaScriptの関数です(jQueryの関数ではありません)。常に何かが動いているゲーム作りには必須です。
$().mousedown(function() {
    if (vx == 1) {vx = 0; vy = 1;}
    else if (vy == 1) {vx = -1; vy = 0;}
    else if (vx == -1) {vx = 0; vy = -1;}
    else if (vy == -1) {vx = 1; vy = 0;}
    return false;
})
マウス押下時に、自機を左回りに90度回転させる処理を行なっています。「$()」このセレクタは「$(document)」の略で、画面全体に対してのマウスイベントを設定しています、たぶん。間違ってたらゴメンナサイ。
最後のreturn false;は、デフォルトのイベントを無効にしています。これによってマウスをクリックしたときに他のボタンが押されたり文字列を選択したりなどの誤動作を防いでいます。
$().mousemove(function() {return false});
こちらはマウス移動時のデフォルトイベントを無効にしています。

mainLoop関数

setIntervalで設定した間隔で繰り返しmainLoop関数が呼ばれます。
px += vx; py += vy;
var item = $('#field_' + px + '_' + py);
if (item.html() != '□') over = true;
item.html('●');
こちらで移動と当たり判定を行なっています。フィールドを作るときにx座標とy座標は各パーツのid内に埋め込んでいますので、ここではプレイヤーの移動先のパーツが空白かどうか調べているだけです。

おわりに

JavaScriptは最近どんどん速くなっていますが、やはりCやFlashでゲームを作るのに比べると遅いので、なるべくプログラムで高速化する必要があります。idによる要素の特定や操作は速い(ハズ)です。

この記事へのトラックバックURL

コメントをどうぞ