ウニボールのソース

// 主人公の向き
var RpgDirection = {
    South:0
    , SouthWest:3
    , West:6
    , SouthEast:9
    , East:12
    , NorthWest:15
    , North:18
    , NorthEast:21
};
// イガイガを避けるゲームのコンストラクタ
var clsSample01 = function()
{
    // ゲームエンジン生成
    this.GameUtl = new clsGameUtl();
    // 主人公チップの幅
    this.ExpCx = 40;
    // 主人公チップの高さ
    this.ExpCy = 56;
    // 主人公の進行方向
    this.ExpDirection = RpgDirection.South;
    // 主人公ロード
    this.Explorer = this.GameUtl.LoadImage('./explorer.png');
    // ボールロード
    this.Ball = this.GameUtl.LoadImage('./uball.png');
}
// 実行
clsSample01.prototype.Run = function()
{
    // キー入力イベントの設定
    window.addEventListener('keydown', this.KeyDown.bind(this));
    // ゲームエンジン初期化
    this.GameUtl.Initialize(this);
    // グリッドレイア
    this.GameUtl.CreateLayer(this.EnterGrid, true, false);
    // 主人公レイア
    this.Hero = this.GameUtl.CreateLayer(this.EnterHero, true, false);
    // ボールレイア
    this.GameUtl.CreateLayer(this.EnterBall, true, false);
}
// グリッドレイアの描画
clsSample01.prototype.EnterGrid = function(ctx, p)
{
    if (!p.EnterGrid) {
        // レイアのサイズを得る
        var sz = this.GameUtl.GetSize();
        // 背景を塗りつぶす
        ctx.fillStyle = "#ccffff";
        ctx.fillRect(0, 0, sz.cx, sz.cy);
        // 水平線
        for (var sy = 0; sy < sz.cy; sy += this.ExpCy) {
              ctx.moveTo(0, sy);
              ctx.lineTo(sz.cx, sy);
              ctx.stroke();
        }
        // 垂直線
        for (var sx = 0; sx < sz.cx; sx += this.ExpCx) {
              ctx.moveTo(sx, 0);
              ctx.lineTo(sx, sz.cy);
              ctx.stroke();
        }
        // 描画は一度のみ
        p.EnterGrid = true;
    }
}
// 主人公レイアの描画
clsSample01.prototype.EnterHero = function(ctx, p)
{
    if (this.Explorer.complete) {
        // fps からフレーム番号を得る
        var frame = this.GameUtl.GetNextFrame(p, 256, this.ExpFrameNum);
        // 描画するコマが変化したなら...
        if (p.Frame != frame) {
            // フレーム番号を記憶する
            p.Frame = frame;
            // レイアのサイズを得る
            var sz = this.GameUtl.GetSize();
            // キャンバスクリア
            ctx.clearRect(0, 0, sz.cx, sz.cy);
            // 画像位置の転送元の位置を設定
            var sx = ((this.ExpDirection % 2) == 0 ? 0 : this.ExpCx * 3) + (p.Frame * this.ExpCx);
            var sy = Math.floor(this.ExpDirection / 6) * this.ExpCy;
            // 画像位置の転送先の位置を設定
            var dx = this.ExpCol * this.ExpCx;
            var dy = this.ExpRow * this.ExpCy;
            // 主人公描画
            if (dx >= 0 && dx < sz.cx && dy >= 0 && dy < sz.cy)
                ctx.drawImage(this.Explorer, sx, sy, this.ExpCx, this.ExpCy, dx, dy, this.ExpCx, this.ExpCy);
        }
    }
}
// ボールレイアの描画
clsSample01.prototype.EnterBall = function(ctx, p)
{
    if (this.Ball.complete) {
        // fps からフレーム番号を得る
        var frame = this.GameUtl.GetNextFrame(p, this.ExpBallSpeed, 4096);
        // 描画するコマが変化したなら...
        if (p.Frame != frame) {
            // フレーム番号を記憶する
            p.Frame = frame;
            // レイアのサイズを得る
            var sz = this.GameUtl.GetSize();
            // 行列の最大値を設定
            var maxRow =  Math.floor(sz.cy / this.ExpCy) - 1;
            var maxCol =  Math.floor(sz.cx / this.ExpCx) - 1;
            // ボールの位置を初期化
            if (!p.BallPos) {
                p.BallPos = {row:maxRow, col:this.Random(0, maxCol), vect:this.Random(0, 3) };
                p.BallAddR = [ -1,  1,  1, -1 ];
                p.BallAddC = [  1,  1, -1, -1 ];
            }
            // 移動後の行列を得る
            var row = p.BallPos.row + p.BallAddR[p.BallPos.vect];
            var col = p.BallPos.col + p.BallAddC[p.BallPos.vect];
            // 枠外に飛び出したフラグ
            var bBound = (row < 0 || row > maxRow || col < 0 || col > maxCol);
            // 枠外に飛び出したら枠内の位置にリセット
            if (bBound) {
                p.BallPos.row = (this.Random(0, 1) == 0 ? 0 : maxRow);
                p.BallPos.col = this.Random(0, maxCol);
                p.BallPos.vect = (p.BallPos.row == 0 ? this.Random(1, 2) : (this.Random(0, 1) == 0 ? 0 : 3));
                // 得点を加算
                $('#score').text(++this.Scored);
            }
            else {
                // 行列を移動
                p.BallPos.row += p.BallAddR[p.BallPos.vect];
                p.BallPos.col += p.BallAddC[p.BallPos.vect];
                // 画像位置の転送先の位置を設定
                var dx = p.BallPos.col * this.ExpCx;
                var dy = p.BallPos.row * this.ExpCy;
                // キャンバスクリア
                ctx.clearRect(0, 0, sz.cx, sz.cy);
                // ボールを描画
                ctx.drawImage(this.Ball, dx, dy, this.ExpCx, this.ExpCy);
                // ゲームオーバー判定
                var bGameOver = (p.BallPos.row == this.ExpRow && p.BallPos.col == this.ExpCol);
                // ゲームオーバーならその旨を表示
                if (bGameOver) {
                    this.GameUtl.aryLayer[this.Hero].prm.Frame = this.ExpFrameNum + 1;
                    this.GameUtl.DrawLayer(this.Hero);
                    this.GameUtl.CanRenderer = false;
                    $('#msg').text(" ★ゲームオーバー★");
                }
            }
        }
        else
            p.Frame = -1;
    }
}
// キー入力
clsSample01.prototype.KeyDown = function(e)
{
    // レイアのサイズを得る
    var sz = this.GameUtl.GetSize();
    // 行列の最大値を設定
    var maxRow =  Math.floor(sz.cy / this.ExpCy) - 1;
    var maxCol =  Math.floor(sz.cx / this.ExpCx) - 1;
    // テンキーは小文字で表現される
    var ch = String.fromCharCode(e.keyCode);
    // キー分岐
    switch (ch) {
        case '2': case 'C':case 'b':    // 下
            this.ExpDirection = RpgDirection.South;
            this.ExpRow += (this.ExpRow + 1 > maxRow ? 0 : 1);
            break;
        case '1': case 'X': case 'a':   // 左下
            this.ExpDirection = RpgDirection.SouthWest;
            this.ExpRow += (this.ExpRow + 1 > maxRow ? 0 : 1);
            this.ExpCol += (this.ExpCol - 1 < 0 ? 0 : -1);
            break;
        case '4': case 'S': case 'd':   // 左
            this.ExpDirection = RpgDirection.West;
            this.ExpCol += (this.ExpCol - 1 < 0 ? 0 : -1);
            break;
        case '3': case 'V': case 'c':   // 右下
            this.ExpDirection = RpgDirection.SouthEast;
            this.ExpRow += (this.ExpRow + 1 > maxRow ? 0 : 1);
            this.ExpCol += (this.ExpCol + 1 > maxCol ? 0 : 1);
            break;
        case '6': case 'F': case 'f':   // 右
            this.ExpDirection = RpgDirection.East;
            this.ExpCol += (this.ExpCol + 1 > maxCol ? 0 : 1);
            break;
        case '7': case 'W': case 'g':   // 左上
            this.ExpDirection = RpgDirection.NorthWest;
            this.ExpRow += (this.ExpRow - 1 < 0 ? 0 : -1);
            this.ExpCol += (this.ExpCol - 1 < 0 ? 0 : -1);
            break;
        case '8': case 'E': case 'h':   // 上
            this.ExpDirection = RpgDirection.North;
            this.ExpRow += (this.ExpRow - 1 < 0 ? 0 : -1);
            break;
        case '9': case 'R': case 'i':   // 右上
            this.ExpDirection = RpgDirection.NorthEast;
            this.ExpCol += (this.ExpCol + 1 > maxCol ? 0 : 1);
            this.ExpRow += (this.ExpRow - 1 < 0 ? 0 : -1);
            break;
        case ' ':
            // ゲーム停止
            this.GameUtl.Stop();
            // ボール速度
            this.ExpBallSpeed = parseInt($('#speed').val());
            // 主人公の行位置
            this.ExpRow = Math.floor(sz.cy / 2 / this.ExpCy);
            // 主人公の列位置
            this.ExpCol = Math.floor(sz.cx / 2 / this.ExpCx);
            // 主人公フレーム数
            this.ExpFrameNum = 3;
            // 得点
            this.Scored = 0;
            // テキスト部クリア
            $('#score').text(this.Scored);
            $('#msg').text(" ");
            // 描画可能を設定
            this.GameUtl.CanRenderer = true;
            // ゲーム開始
            this.GameUtl.DoGame();
            break;
    }
    // デフォルトイベントをキャンセルする
    e.preventDefault();
}
// min から max までの乱整数を返す関数
clsSample01.prototype.Random = function(min, max) {
    return Math.floor(Math.random() * (max - min + 1)) + min;
}