liguofeng29’s blog

個人勉強用ブログだっす。

テトリスサンプル

<!DOCTYPE html>
<html>
<head>
   <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
   <title>テトリス</title>
   <script type="text/javascript" src="tetris.js">
   </script>
   <style type="text/css">
        body>div {
            font-size:13pt;
            padding-bottom: 8px;
        }
        span {
            font-family: tmb;
            font-size:20pt;
            color: green;
        }
    </style>
</head>
<body>
<div style="width:336px;border:1px solid black;background:#ff9;">&nbsp;
<div style="float:left;">速度:<span id="curSpeedEle"></span>
得点:<span id="curScoreEle"></span></div>
<div style="float:right;">最高得点:<span id="maxScoreEle"></span></div>
</div>
</body>
</html>

tetris.js

var TETRIS_ROWS = 20; // 行数(偶数)
var TETRIS_COLS = 14; // 列数(偶数)
var CELL_SIZE = 24; // 位置ブロックのサイズ
var NO_BLOCK = 0; // 空状態
var curScore = 0; // 現在の得点
var curSpeed = 1; // 現在の速度
var maxScore = 0; // 最高得点
var isPlaying = true; // ゲーム中
// 固定されているブロック
var tetris_status = [];
var curTimer;
// DOM
var tetris_canvas;
var tetris_ctx;
var curScoreEle, curSpeedEle, maxScoreEle;
var currentFall; // 現在のブロック

// 固定されているブロック初期化
for (var i = 0; i < TETRIS_ROWS; i++) {
    tetris_status[i] = [];
    for (var j = 0; j < TETRIS_COLS; j++) {
        tetris_status[i][j] = NO_BLOCK;
    }
}
// 色
colors = ["#fff", "#f00", "#0f0", "#00f", "#c60", "#f0f", "#0ff", "#609"];
// 初期で生成されるブロックの種類
var blockArr = [
    // Z
    [{
        x: TETRIS_COLS / 2 - 1,
        y: 0,
        color: 1
    }, {
        x: TETRIS_COLS / 2,
        y: 0,
        color: 1
    }, {
        x: TETRIS_COLS / 2,
        y: 1,
        color: 1
    }, {
        x: TETRIS_COLS / 2 + 1,
        y: 1,
        color: 1
    }],
    // 逆Z
    [{
        x: TETRIS_COLS / 2 + 1,
        y: 0,
        color: 2
    }, {
        x: TETRIS_COLS / 2,
        y: 0,
        color: 2
    }, {
        x: TETRIS_COLS / 2,
        y: 1,
        color: 2
    }, {
        x: TETRIS_COLS / 2 - 1,
        y: 1,
        color: 2
    }],
    // 田
    [{
        x: TETRIS_COLS / 2 - 1,
        y: 0,
        color: 3
    }, {
        x: TETRIS_COLS / 2,
        y: 0,
        color: 3
    }, {
        x: TETRIS_COLS / 2 - 1,
        y: 1,
        color: 3
    }, {
        x: TETRIS_COLS / 2,
        y: 1,
        color: 3
    }],
    // L
    [{
        x: TETRIS_COLS / 2 - 1,
        y: 0,
        color: 4
    }, {
        x: TETRIS_COLS / 2 - 1,
        y: 1,
        color: 4
    }, {
        x: TETRIS_COLS / 2 - 1,
        y: 2,
        color: 4
    }, {
        x: TETRIS_COLS / 2,
        y: 2,
        color: 4
    }],
    // J
    [{
        x: TETRIS_COLS / 2,
        y: 0,
        color: 5
    }, {
        x: TETRIS_COLS / 2,
        y: 1,
        color: 5
    }, {
        x: TETRIS_COLS / 2,
        y: 2,
        color: 5
    }, {
        x: TETRIS_COLS / 2 - 1,
        y: 2,
        color: 5
    }],
    // l
    [{
        x: TETRIS_COLS / 2,
        y: 0,
        color: 6
    }, {
        x: TETRIS_COLS / 2,
        y: 1,
        color: 6
    }, {
        x: TETRIS_COLS / 2,
        y: 2,
        color: 6
    }, {
        x: TETRIS_COLS / 2,
        y: 3,
        color: 6
    }],
    // ㅗ
    [{
        x: TETRIS_COLS / 2,
        y: 0,
        color: 7
    }, {
        x: TETRIS_COLS / 2 - 1,
        y: 1,
        color: 7
    }, {
        x: TETRIS_COLS / 2,
        y: 1,
        color: 7
    }, {
        x: TETRIS_COLS / 2 + 1,
        y: 1,
        color: 7
    }]
];
// ブロック処理化
var initBlock = function() {
    var rand = Math.floor(Math.random() * blockArr.length);
    // 現在のブロックをランダム生成
    currentFall = [{
        x: blockArr[rand][0].x,
        y: blockArr[rand][0].y,
        color: blockArr[rand][0].color
    }, {
        x: blockArr[rand][1].x,
        y: blockArr[rand][1].y,
        color: blockArr[rand][1].color
    }, {
        x: blockArr[rand][2].x,
        y: blockArr[rand][2].y,
        color: blockArr[rand][2].color
    }, {
        x: blockArr[rand][3].x,
        y: blockArr[rand][3].y,
        color: blockArr[rand][3].color
    }];
};
// ゲーム領域生成
var createCanvas = function(rows, cols, cellWidth, cellHeight) {
        tetris_canvas = document.createElement("canvas");
        tetris_canvas.width = cols * cellWidth;
        tetris_canvas.height = rows * cellHeight;
        tetris_canvas.style.border = "1px solid black";
        tetris_ctx = tetris_canvas.getContext('2d');
        tetris_ctx.beginPath();
        for (var i = 1; i < TETRIS_ROWS; i++) {
            tetris_ctx.moveTo(0, i * CELL_SIZE);
            tetris_ctx.lineTo(TETRIS_COLS * CELL_SIZE, i * CELL_SIZE);
        }
        for (var i = 1; i < TETRIS_COLS; i++) {
            tetris_ctx.moveTo(i * CELL_SIZE, 0);
            tetris_ctx.lineTo(i * CELL_SIZE, TETRIS_ROWS * CELL_SIZE);
        }
        tetris_ctx.closePath();
        tetris_ctx.strokeStyle = "#aaa";
        tetris_ctx.lineWidth = 0.3;
        tetris_ctx.stroke();
    }
// 再描画
var drawBlock = function() {
        // 全体再描画
        for (var i = 0; i < TETRIS_ROWS; i++) {
            for (var j = 0; j < TETRIS_COLS; j++) {
                // ブロックあり
                if (tetris_status[i][j] != NO_BLOCK) {
                    // 色
                    tetris_ctx.fillStyle = colors[tetris_status[i][j]];
                }
                // ブロックなし
                else {
                    // 白色
                    tetris_ctx.fillStyle = 'white';
                }
                // 描く
                tetris_ctx.fillRect(j * CELL_SIZE + 1, i * CELL_SIZE + 1, CELL_SIZE - 2, CELL_SIZE - 2);
            }
        }
    }
// onloadリスナー
window.onload = function() {
        // canvasラ生成
        createCanvas(TETRIS_ROWS, TETRIS_COLS, CELL_SIZE, CELL_SIZE);
        document.body.appendChild(tetris_canvas);
        curScoreEle = document.getElementById("curScoreEle");
        curSpeedEle = document.getElementById("curSpeedEle");
        maxScoreEle = document.getElementById("maxScoreEle");
        // ローカルストレージ
        var tmpStatus = localStorage.getItem("tetris_status");
        tetris_status = tmpStatus == null ? tetris_status : JSON.parse(tmpStatus);
        // ブロック再描画
        drawBlock();
        // 現在得点
        curScore = localStorage.getItem("curScore");
        curScore = curScore == null ? 0 : parseInt(curScore);
        curScoreEle.innerHTML = curScore;
        // 最高得点
        maxScore = localStorage.getItem("maxScore");
        maxScore = maxScore == null ? 0 : parseInt(maxScore);
        maxScoreEle.innerHTML = maxScore;
        // 現在速度
        curSpeed = localStorage.getItem("curSpeed");
        curSpeed = curSpeed == null ? 1 : parseInt(curSpeed);
        curSpeedEle.innerHTML = curSpeed;
        // 固定された領域初期化
        initBlock();
        // 落下
        curTimer = setInterval("moveDown();", 500 / curSpeed);
    }
// 一行が埋まった処理
var lineFull = function() {
        // 行繰り返し
        for (var i = 0; i < TETRIS_ROWS; i++) {
            var flag = true;
            // 列繰り返し
            for (var j = 0; j < TETRIS_COLS; j++) {
                if (tetris_status[i][j] == NO_BLOCK) {
                    flag = false;
                    break;
                }
            }
            // 埋まった
            if (flag) {
                // 得点
                curScoreEle.innerHTML = curScore += 100;
                // ローカルストレージに保存
                localStorage.setItem("curScore", curScore);
                // 速度あげ
                if (curScore >= curSpeed * curSpeed * 500) {
                    curSpeedEle.innerHTML = curSpeed += 1;
                    // ハケモテLocal StorageシヌツシcurSpeed。」
                    localStorage.setItem("curSpeed", curSpeed);
                    clearInterval(curTimer);
                    curTimer = setInterval("moveDown();", 500 / curSpeed);
                }
                // 行を一段下に移動
                for (var k = i; k > 0; k--) {
                    for (var l = 0; l < TETRIS_COLS; l++) {
                        tetris_status[k][l] = tetris_status[k - 1][l];
                    }
                }
                // 消す
                drawBlock();
            }
        }
    }
//落下
var moveDown = function() {
        // 移動可能か
        var canDown = true;
        // 
        for (var i = 0; i < currentFall.length; i++) {
            // 下に着いた
            if (currentFall[i].y >= TETRIS_ROWS - 1) {
                canDown = false;
                break;
            }
            // 下にブロックある
            if (tetris_status[currentFall[i].y + 1][currentFall[i].x] != NO_BLOCK) {
                canDown = false;
                break;
            }
        }
        // 移動可能
        if (canDown) {
            // 移動前白塗り
            for (var i = 0; i < currentFall.length; i++) {
                var cur = currentFall[i];
                tetris_ctx.fillStyle = 'white';
                tetris_ctx.fillRect(cur.x * CELL_SIZE + 1, cur.y * CELL_SIZE + 1, CELL_SIZE - 2, CELL_SIZE - 2);
            }
            // 移動
            for (var i = 0; i < currentFall.length; i++) {
                var cur = currentFall[i];
                cur.y++;
            }
            // 移動後色塗り
            for (var i = 0; i < currentFall.length; i++) {
                var cur = currentFall[i];
                tetris_ctx.fillStyle = colors[cur.color];
                tetris_ctx.fillRect(cur.x * CELL_SIZE + 1, cur.y * CELL_SIZE + 1, CELL_SIZE - 2, CELL_SIZE - 2);
            }
        }
        // 移動不可
        else {
            // 固定ブロックに記録
            for (var i = 0; i < currentFall.length; i++) {
                var cur = currentFall[i];
                // ゲーム終了
                if (cur.y < 2) {
                    // ローカルストレージ保存
                    localStorage.removeItem("curScore");
                    localStorage.removeItem("tetris_status");
                    localStorage.removeItem("curSpeed");
                    if (confirm("Game Over!")) {
                        // 最高得点
                        maxScore = localStorage.getItem("maxScore");
                        maxScore = maxScore == null ? 0 : maxScore;
                        if (curScore >= maxScore) {
                            localStorage.setItem("maxScore", curScore);
                        }
                    }
                    // 終了フラグ
                    isPlaying = false;
                    // タイマークリア
                    clearInterval(curTimer);
                    return;
                }
                tetris_status[cur.y][cur.x] = cur.color;
            }
            // 一行埋まったか
            lineFull();
            localStorage.setItem("tetris_status", JSON.stringify(tetris_status));
            // ブロック生成
            initBlock();
        }
    }
// 左移動
var moveLeft = function() {
        // 移動可能
        var canLeft = true;
        for (var i = 0; i < currentFall.length; i++) {
            // 一番左
            if (currentFall[i].x <= 0) {
                canLeft = false;
                break;
            }
            // 左にブロックあり
            if (tetris_status[currentFall[i].y][currentFall[i].x - 1] != NO_BLOCK) {
                canLeft = false;
                break;
            }
        }
        // 移動可能
        if (canLeft) {
            // 移動前白塗り
            for (var i = 0; i < currentFall.length; i++) {
                var cur = currentFall[i];
                tetris_ctx.fillStyle = 'white';
                tetris_ctx.fillRect(cur.x * CELL_SIZE + 1, cur.y * CELL_SIZE + 1, CELL_SIZE - 2, CELL_SIZE - 2);
            }
            // 移動
            for (var i = 0; i < currentFall.length; i++) {
                var cur = currentFall[i];
                cur.x--;
            }
            // 移動後色塗り
            for (var i = 0; i < currentFall.length; i++) {
                var cur = currentFall[i];
                tetris_ctx.fillStyle = colors[cur.color];
                tetris_ctx.fillRect(cur.x * CELL_SIZE + 1, cur.y * CELL_SIZE + 1, CELL_SIZE - 2, CELL_SIZE - 2);
            }
        }
    }
// 右移動
var moveRight = function() {
        // 右移動可能か
        var canRight = true;
        for (var i = 0; i < currentFall.length; i++) {
            // 一番右
            if (currentFall[i].x >= TETRIS_COLS - 1) {
                canRight = false;
                break;
            }
            // 右にブロックあり
            if (tetris_status[currentFall[i].y][currentFall[i].x + 1] != NO_BLOCK) {
                canRight = false;
                break;
            }
        }
        // 移動可能
        if (canRight) {
            // 移動前白塗り
            for (var i = 0; i < currentFall.length; i++) {
                var cur = currentFall[i];
                tetris_ctx.fillStyle = 'white';
                tetris_ctx.fillRect(cur.x * CELL_SIZE + 1, cur.y * CELL_SIZE + 1, CELL_SIZE - 2, CELL_SIZE - 2);
            }
            // 移動
            for (var i = 0; i < currentFall.length; i++) {
                var cur = currentFall[i];
                cur.x++;
            }
            // 移動後色塗り
            for (var i = 0; i < currentFall.length; i++) {
                var cur = currentFall[i];
                tetris_ctx.fillStyle = colors[cur.color];
                tetris_ctx.fillRect(cur.x * CELL_SIZE + 1, cur.y * CELL_SIZE + 1, CELL_SIZE - 2, CELL_SIZE - 2);
            }
        }
    }
// 回転
var rotate = function() {
    // 回転可能
    var canRotate = true;
    for (var i = 0; i < currentFall.length; i++) {
        var preX = currentFall[i].x;
        var preY = currentFall[i].y;
        // 第3ブロックを中心に回転
        if (i != 2) {
            // x,y計算
            var afterRotateX = currentFall[2].x + preY - currentFall[2].y;
            var afterRotateY = currentFall[2].y + currentFall[2].x - preX;
            // ネ郢鋗�ラェコレホサヨテメムモミキスソ鬟ャア��サトワミ�ラェ
            if (tetris_status[afterRotateY][afterRotateX + 1] != NO_BLOCK) {
                canRotate = false;
                break;
            }
            // 左超えた場合
            if (afterRotateX < 0 || tetris_status[afterRotateY - 1][afterRotateX] != NO_BLOCK) {
                moveRight();
                afterRotateX = currentFall[2].x + preY - currentFall[2].y;
                afterRotateY = currentFall[2].y + currentFall[2].x - preX;
                break;
            }
            if (afterRotateX < 0 || tetris_status[afterRotateY - 1][afterRotateX] != NO_BLOCK) {
                moveRight();
                break;
            }
            // 右を超えた場合
            if (afterRotateX >= TETRIS_COLS - 1 ||
                tetris_status[afterRotateY][afterRotateX + 1] != NO_BLOCK) {
                moveLeft();
                afterRotateX = currentFall[2].x + preY - currentFall[2].y;
                afterRotateY = currentFall[2].y + currentFall[2].x - preX;
                break;
            }
            if (afterRotateX >= TETRIS_COLS - 1 ||
                tetris_status[afterRotateY][afterRotateX + 1] != NO_BLOCK) {
                moveLeft();
                break;
            }
        }
    }
    // 回転可能
    if (canRotate) {
        // 回転前にすべて白
        for (var i = 0; i < currentFall.length; i++) {
            var cur = currentFall[i];
            tetris_ctx.fillStyle = 'white';
            tetris_ctx.fillRect(cur.x * CELL_SIZE + 1, cur.y * CELL_SIZE + 1, CELL_SIZE - 2, CELL_SIZE - 2);
        }
        for (var i = 0; i < currentFall.length; i++) {
            var preX = currentFall[i].x;
            var preY = currentFall[i].y;
            // 第3ブロック中心
            if (i != 2) {
                currentFall[i].x = currentFall[2].x +
                    preY - currentFall[2].y;
                currentFall[i].y = currentFall[2].y +
                    currentFall[2].x - preX;
            }
        }
        // 回転後色塗り
        for (var i = 0; i < currentFall.length; i++) {
            var cur = currentFall[i];
            tetris_ctx.fillStyle = colors[cur.color];
            tetris_ctx.fillRect(cur.x * CELL_SIZE + 1, cur.y * CELL_SIZE + 1, CELL_SIZE - 2, CELL_SIZE - 2);
        }
    }
}
window.focus();
// keydownイベント
window.onkeydown = function(evt) {
    switch (evt.keyCode) {
        // ↓
        case 40:
            if (!isPlaying)
                return;
            moveDown(); // 下移動
            break;
            // ←
        case 37:
            if (!isPlaying)
                return;
            moveLeft(); // 左移動
            break;
            // →
        case 39:
            if (!isPlaying)
                return;
            moveRight(); // 右移動
            break;
            // ↑
        case 38:
            if (!isPlaying)
                return;
            rotate(); // 回転
            break;
    }
}

http://f.st-hatena.com/images/fotolife/l/liguofeng29/20160220/20160220204602.gif?1455969062