第7回 もぐらたたきっぽいゲーム – jQuery入門

2009 年 5 月 11 日 投稿者: naga3

jQuery入門の第7回目です。私もJavaScriptの書き方に少しだけ慣れてきたので、今回は前回までのCっぽい書き方じゃなく、少しだけJavaScript黒魔術っぽい書き方をやってみようと思います。
今回のゲームは画面上を複数のチェックボックスが浮遊しているので、それを素早くチェックする、というものです。チェックボックスというのは動かない、と相場が決まっているので、動くとそれだけで異様な感じがして面白いかもです。

チェックボックスたたき

画面上を浮遊する全てのチェックボックスをチェックすると、クリアするまでに経過した時間が表示されます。

チェックボックスたたきのソース

使用するリソース(右クリックで保存してください)
HTML
<!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">
$(function() {
    $('a').click(function() {
        var NUM = 5;            // チェックボックス数
        var SIZE = 200;        // ステージの大きさ
        var count = 0;        // 現在チェックされている数
        var st = new Date().getTime();    // 開始時間
        $('body').empty();

        // チェックボックスの新しい位置を返す。
        function newPos() {
            return {
                left: Math.floor(Math.random() * SIZE),
                top: Math.floor(Math.random() * SIZE)
            };
        }

        // チェックボックスの生成・アニメーションの設定
        for (var i = 0; i < NUM; i++) {
            $('<input type="checkbox" />')
            .appendTo('body')
            .css('position', 'absolute')
            .css(newPos())
            .each(function() {
                $(this).animate(newPos(), 3000, arguments.callee);
            });
        }

        // チェックボックスが押されたときの処理
        $('input').click(function() {
            $(this).stop().attr('disabled', 'disabled');
            var t = Math.floor((new Date().getTime() - st) / 1000);
            if (++count >= NUM) alert('クリア!所要時間:' + t + '秒');
        });

        return false;
    });
});
</script>
</head>
<body>
<a href="#">素早く全てクリックするのだ!</a>
</body>
</html>

プログラムの解説

レキシカル変数

$('a').click(function() {
    var NUM = 5;            // チェックボックス数
    var SIZE = 200;        // ステージの大きさ
    var count = 0;        // 現在チェックされている数
    var st = new Date().getTime();    // 開始時間
aタグのclickイベント関数上部に、変数がいくつが定義してあります。普通、関数内で定義したローカル変数は関数の実行が終了すると消えてしまいますが、JavaScriptの場合はレキシカル変数と言って、関数内に定義した関数(例えばnewPosや$(‘input’).click)からは親関数が終わったあとでも参照・変更できるのです。すごいね。
var NUM = 5;            // チェックボックス数
var SIZE = 200;        // ステージの大きさ
浮遊するチェックボックスの数とステージの大きさ(縦横同じピクセル数)です。こういった変動しない値は定数にすべきですが、JavaScriptの「const」はIEじゃ動かないんですよねー。
var st = new Date().getTime();    // 開始時間
チェックボックスの全てのチェックが完了するまでの時間を計るため、ゲーム開始時の時間を保存しています。new Date()によって現在時刻を保持したオブジェクトを生成し、getTimeメソッドでその時刻をミリ秒で取得しstに代入しています。

チェックボックスの新しい位置をランダムで決める

function newPos() {
    return {
        left: Math.floor(Math.random() * SIZE),
        top: Math.floor(Math.random() * SIZE)
    };
}
チェックボックスの位置をランダムで生成してCSSのハッシュとして返す関数です。今回、「チェックボックスの最初の位置決め」「次のアニメーション用の位置決め」の2箇所でleft,topプロパティを設定しなければいけない部分が出てくるので関数にしてみました。戻り値はハッシュ「{left: xxx, top: xxx}」形式なので注意してください。「Math.floor(Math.random() * SIZE)」は非常によくある書き方で、0以上SIZE未満の整数が得られます。

チェックボックス生成&アニメーション設定

for (var i = 0; i < NUM; i++) {
    $('<input type="checkbox" />')
    .appendTo('body')
    .css('position', 'absolute')
    .css(newPos())
    .each(function() {
        $(this).animate(newPos(), 3000, arguments.callee);
    });
}
この部分でチェックボックスの生成と、アニメーションの設定をまとめて行なっています。チェックボックスの生成は
$('body').append('<input type="checkbox" />');
と書く方が多いと思うのですが、今回はappendToによってbody要素に追加し、その後メソッドチェーンを繋げてCSSの設定とアニメーションの設定を一気に行なっています。
.each(function() {
    $(this).animate(newPos(), 3000, arguments.callee);
});
eachはjQueryオブジェクトにそれぞれに対して、順番に関数を実行するものなのですが・・・今回はオブジェクトがひとつしかないのでeachの意味はありません。他にうまい書き方が思いつかなかったのですすみません。
arguments.calleeは実行している関数自体を指します。匿名関数の再帰処理などでよく使われるそうです。アニメーションが終わった後に同じ関数を割り当てたかったので使ってみました。
$('input').click(function() {
    $(this).stop().attr('disabled', 'disabled');
    var t = Math.floor((new Date().getTime() - st) / 1000);
    if (++count >= NUM) alert('クリア!所要時間:' + t + '秒');
});
各チェックボックスが押されたときに呼ばれる部分です。
まずstop()でチェックボックスのアニメーションを止め、attrメソッドでチェックを出来なくしています。
その後現在時刻からゲーム開始時刻を引いて所要時間を割り出しています。
return false;
最後のreturn false;は、aタグのデフォルトの動作を無効にしています。href=”#”にジャンプする部分ですね。

まとめ

・レキシカル変数を使うとスコープを狭めてグローバル変数的な使い方ができる。
・JavaScriptのハッシュは強力。jQueryの引数でハッシュを渡すものが沢山ある。
・arguments.calleeは現在呼ばれている関数自体を指す。

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

コメントをどうぞ