html5實現的一個俄羅斯方塊示例

haiyangyiba 8年前發布 | 40K 次閱讀 俄羅斯方塊 HTML5 前端技術

示例簡單,運行地址為:http://chendd.cn/demo/html/canvas/elsfk.html,得需要支持html5瀏覽器的環境。

實現的功能:方塊旋轉(W鍵)、自動下落、移動(ASD)、消行、快速下落(空格鍵)、下落陰影、游戲結束。

為實現功能:消行時的計分、等級、以及不同等級的下落速度等。

學習了xiaoE的Java版本的俄羅斯方塊后,自己動手使用html5的canvas實現的,

參考效果圖如下:

詳細代碼如下:


<!DOCTYPE html>

<html>

    <head>

        <meta charset="utf-8">

        <title>俄羅斯方塊</title>

        <style type="text/css">
            /*整個畫布*/

            #tetris {
                border: 6px solid grey;
            }
            /*游戲面板*/
        </style>

    </head>

    <body>

        <canvas id="tetris" width="565" height="576"></canvas>

        <script type="text/javascript">
            var canvas = document.getElementById("tetris");
            var context = canvas.getContext("2d");
            var padding = 6,
                size = 32,
                minX = 0,
                maxX = 10,
                minY = 0,
                maxY = 18,
                score = 0,
                level = 1;
            var gameMap = new Array(); //游戲地圖,二維數組
            var gameTimer;
            initGameMap();
            //繪制垂直線條
            drawGrid();
            var arrays = basicBlockType();
            var blockIndex = getRandomIndex();
            //隨機畫一個方塊意思意思
            var block = getPointByCode(blockIndex);
            context.fillStyle = getBlockColorByIndex(blockIndex);
            drawBlock(block);
            /**

             * 初始化游戲地圖

             */
            function initGameMap() {
                for (var i = 0; i < maxY; i++) {
                    var row = new Array();
                    for (var j = 0; j < maxX; j++) {
                        row[j] = false;
                    }
                    gameMap[i] = row;
                }
            }
            /**

             * 方塊旋轉

             * 順時針:

             * A.x =O.y + O.x - B.y

             * A.y =O.y - O.x + B.x

             */
            function round() {
                //正方形的方塊不響應旋轉   
                if (blockIndex == 4) {
                    return;
                }
                //循環處理當前的方塊,找新的旋轉點
                for (var i = 1; i < block.length; i++) {
                    var o = block[0];
                    var point = block[i];
                    //旋轉后的位置不能與現有格子的方塊沖突
                    var tempX = o.y + o.x - point.y;
                    var tempY = o.y - o.x + point.x;
                    if (isOverZone(tempX, tempY)) {
                        return; //不可旋轉
                    }
                }
                clearBlock();
                //可以旋轉,設置新的旋轉后的坐標
                for (var i = 1; i < block.length; i++) {
                    var o = block[0];
                    var point = block[i];
                    //旋轉后的位置不能與現有格子的方塊沖突
                    var tempX = o.y + o.x - point.y;
                    var tempY = o.y - o.x + point.x;
                    block[i] = {
                        x: tempX,
                        y: tempY
                    };
                }
                drawBlock();
            }
            function moveDown() {

                var overFlag = canOver();
                if(overFlag){
                    //如果不能向下移動了,將當前的方塊坐標載入地圖
                    window.clearInterval(gameTimer);
                    add2GameMap();
                    //清除游戲區域內的不同顏色的格子,使用單一顏色重新繪制地圖堆積物
                    redrawGameMap();
                    return;//游戲結束
                }

                var flag = moveTo(0, 1);
                //如果可以移動,則繼續移動
                if (flag) {
                    return;
                }
                //如果不能向下移動了,將當前的方塊坐標載入地圖
                add2GameMap();

                //進行消行動作
                clearLines();
                //清除游戲區域內的不同顏色的格子,使用單一顏色重新繪制地圖堆積物
                redrawGameMap();
                //如果不能向下移動,則繼續下一個方塊
                nextBlock();
            }

            /**

             * 消行動作,返回消除的行數

             */
            function clearLines() {
                var clearRowList = new Array();
                for (var i = 0; i < maxY; i++) {
                    var flag = true;
                    for (var j = 0; j < maxX; j++) {
                        if (gameMap[i][j] == false) {
                            flag = false;
                            break;
                        }
                    }
                    if (flag) {
                        clearRowList.push(i); //記錄消除行號的索引
                    }
                }
                var clearRows = clearRowList.length;
                //所謂的消行就是將待消除行的索引,下方所有的格子上移動
                for (var x = 0; x < clearRows; x++) {
                    var index = clearRowList[x];
                    for (var i = index; i > 0; i--) {
                        for (var j = 0; j < maxX; j++) {
                            gameMap[i][j] = gameMap[i - 1][j];
                        }
                    }
                }
                if (clearRows > 0) {
                    for (var i = 0; i < maxY; i++) {
                        //此處可以限制滿足相關條件的方塊進行清除操作&& j < clearRowList[clearRows - 1]
                        for (var j = 0; j < maxX; j++) {
                            if (gameMap[i][j] == false) {
                                clearBlockByPoint(i, j);
                            }
                        }
                    }
                }
            }
            /**

             * 重繪游戲地圖

             */
            function redrawGameMap() {
                drawGrid();
                for (var i = 0; i < maxY; i++) {
                    for (var j = 0; j < maxX; j++) {
                        if (gameMap[i][j]) {
                            roadBlock(j, i);
                        }
                    }
                }
            }
            /**

             * 打印陰影地圖

             */
            function drawShadowBlock() {
                var currentBlock = block;
                var shadowPoints = getCanMoveDown();
                if (shadowPoints != null && shadowPoints.length > 0) {
                    for (var i = 0; i < shadowPoints.length; i++) {
                        var point = shadowPoints[i];
                        if (point == null) {
                            continue;
                        }
                        var start = point.x * size;
                        var end = point.y * size;
                        context.fillStyle = "#abcdef";
                        context.fillRect(start, end, size, size);
                        context.strokeStyle = "black";
                        context.strokeRect(start, end, size, size);
                    }
                }
            }
            /**

             * 返回最多可移動到的坐標位置(統計總共可以下落多少步驟)

             * @return最多可移動到的坐標位置

             */
            function getCanMoveDown() {
                var nps = canMove(0, 1, block);
                var last = null;
                if (nps != null) {
                    last = new Array();
                    while ((nps = canMove(0, 1, nps)) != null) {
                        if (nps != null) {
                            last = nps;
                        }
                    }
                }
                return last;
            }

            function canOver(){
                var flag = false;
                for (var i = 0; i < block.length; i++) {
                    var point = block[i];
                    var x = point.x;
                    var y = point.y;
                    if(isOverZone(x , y)){
                        flag = true;
                        break;
                    }
                }
                return flag;
            }

            function drawLevelScore() {

            }
            /**

             * 將不能移動的各種填充至地圖

             */
            function add2GameMap() {
                for (var i = 0; i < block.length; i++) {
                    var point = block[i];
                    var x = point.x;
                    var y = point.y;
                    var gameMapRow = gameMap[y]; //獲取到地圖的一行
                    gameMapRow[x] = true; //將此行中的某個格子標記為堆積物
                    gameMap[y] = gameMapRow; //再將行給設置回來
                }
            }
            function moveLeft() {
                moveTo(-1, 0);
            }
            function moveRight() {
                moveTo(1, 0);
            }
            function quickDown() {
                while (moveTo(0, 1));
            }
            function moveTo(moveX, moveY) {
                var move = canMove(moveX, moveY, block); //判定是否可以移動
                if (move == null) {
                    return false;
                }
                clearBlock();
                for (var i = 0; i < block.length; i++) {
                    var point = block[i];
                    point.x = point.x + moveX;
                    point.y = point.y + moveY;
                }
                drawBlock();
                return true;
            }
            /**

             * 下一個方塊

             */
            function nextBlock() {
                blockIndex = getRandomIndex();
                block = getPointByCode(blockIndex);
                context.fillStyle = getBlockColorByIndex(blockIndex);
                drawBlock();
            }
            document.onkeypress = function(evt) {
                var key = window.event ? evt.keyCode : evt.which;
                switch (key) {
                    case 119: //向上旋轉 W
                        round();
                        break;
                    case 115: //向下移動  S
                        moveDown();
                        break;
                    case 97: //向左移動 A
                        moveLeft();
                        break;
                    case 100: //向右移動 D
                        moveRight();
                        break;
                    case 32: //空格鍵快速下落到底
                        quickDown();
                        break;
                }
            }
            /**

             * 判定是否可以移動

             * @parammoveX 橫向移動的個數

             * @parammoveY 縱向移動的個數

             */
            function canMove(moveX, moveY, currentBlock) {
                var flag = true;
                var newPoints = new Array();
                for (var i = 0; i < currentBlock.length; i++) {
                    var point = currentBlock[i];
                    var tempX = point.x + moveX;
                    var tempY = point.y + moveY;
                    if (isOverZone(tempX, tempY)) {
                        flag = false;
                        break;
                    }
                }
                if (flag) {
                    for (var i = 0; i < currentBlock.length; i++) {
                        var point = currentBlock[i];
                        var tempX = point.x + moveX;
                        var tempY = point.y + moveY;
                        newPoints[i] = {
                            x: tempX,
                            y: tempY
                        };
                    }
                    return newPoints;
                }
                return null;
            }
            /**

             * 判定是否可以移動

             * @paramx 預移動后的橫坐標

             * @paramy 預移動后的縱坐標

             */
            function isOverZone(x, y) {
                return x < minX || x >= maxX || y < minY || y >= maxY || gameMap[y][x];
            }
            document.body.click();

            gameTimer = window.setInterval(moveDown , 800);

            /**

             * 初始化方塊的基礎數據

             */
            function basicBlockType() {
                var arrays = new Array();
                arrays[0] = [{
                    x: 4,
                    y: 0
                }, {
                    x: 3,
                    y: 0
                }, {
                    x: 5,
                    y: 0
                }, {
                    x: 6,
                    y: 0
                }];
                arrays[1] = [{
                    x: 4,
                    y: 0
                }, {
                    x: 3,
                    y: 0
                }, {
                    x: 5,
                    y: 0
                }, {
                    x: 4,
                    y: 1
                }];
                arrays[2] = [{
                    x: 4,
                    y: 0
                }, {
                    x: 3,
                    y: 0
                }, {
                    x: 5,
                    y: 0
                }, {
                    x: 3,
                    y: 1
                }];
                arrays[3] = [{
                    x: 4,
                    y: 0
                }, {
                    x: 5,
                    y: 0
                }, {
                    x: 3,
                    y: 1
                }, {
                    x: 4,
                    y: 1
                }];
                arrays[4] = [{
                    x: 4,
                    y: 0
                }, {
                    x: 5,
                    y: 0
                }, {
                    x: 4,
                    y: 1
                }, {
                    x: 5,
                    y: 1
                }];
                arrays[5] = [{
                    x: 4,
                    y: 0
                }, {
                    x: 3,
                    y: 0
                }, {
                    x: 5,
                    y: 0
                }, {
                    x: 5,
                    y: 1
                }];
                arrays[6] = [{
                    x: 4,
                    y: 0
                }, {
                    x: 3,
                    y: 0
                }, {
                    x: 4,
                    y: 1
                }, {
                    x: 5,
                    y: 1
                }];
                return arrays;
            }
            function basicBlockColor() {
                return ["#A00000", "#A05000", "#A0A000", "#00A000", "#00A0A0", "#0000A0", "#A000A0"];
            }
            function getBlockColorByIndex(typeCodeIndex) {
                var arrays = basicBlockColor();
                return arrays[typeCodeIndex];
            }
            /**

             * 根據編號返回指定編號的方塊

             * @paramtypeCodeIndex 方塊編號索引

             */
            function getPointByCode(typeCodeIndex) {
                var arrays = basicBlockType();
                return arrays[typeCodeIndex];
            }
            /**

             * 獲取隨即出現方塊的范圍值

             * @paramlens 隨機數的范圍

             */
            function getRandomIndex() {
                return parseInt(Math.random() * (arrays.length - 1), 10);
            }
            /**

             * 繪制方塊,按格子單個繪制

             */
            function drawBlock() {
                drawGrid();
                for (var i = 0; i < block.length; i++) {
                    var point = block[i];
                    var start = point.x * size;
                    var end = point.y * size;
                    context.fillStyle = getBlockColorByIndex(blockIndex);
                    context.fillRect(start, end, size, size);
                    context.strokeStyle = "black";
                    context.strokeRect(start, end, size, size);
                }
                drawShadowBlock();
            }
            /**

             * 繪制障礙物

             */
            function roadBlock(x, y) {
                context.fillStyle = "darkgray";
                var start = x * size;
                var end = y * size;
                context.fillRect(start, end, size, size);
            }
            /**

             * 繪制新的方塊先清除之前的方塊

             */
            function clearBlock() {
                for (var i = 0; i < block.length; i++) {
                    var point = block[i];
                    var start = point.x * size;
                    var end = point.y * size;
                    context.clearRect(start, end, size, size);
                }
            }
            /**

             * 初始化一個新的行

             */
            function initGameMapRow() {
                var array = new Array();
                for (var i = 0; i < maxX; i++) {
                    array[i] = false;
                }
                return array;
            }
            /**

             * 根據坐標清除指定格子的內容

             * @paramx 橫坐標

             * @paramy 縱坐標

             */
            function clearBlockByPoint(x, y) {
                var start = y * size;
                var end = x * size;
                context.clearRect(start, end, size, size);
            }
            /**

             * 清掉所有位置的空白格的繪圖

             */
            function clearAllNullPoint() {
                for (var i = 0; i < maxY; i++) {
                    for (var j = 0; j < maxX; j++) {
                        if (gameMap[i][j] == false) {
                            clearBlockByPoint(i, j);
                        }
                    }
                }
            }
            /**

             * 繪制網格線

             * @paramcontext 繪圖對象

             */
            function drawGrid() {
                clearAllNullPoint(); //清除掉當前方塊下落位置造成的陰影
                context.strokeStyle = "grey"; //畫筆顏色
                for (var i = 0; i <= maxX; i++) {
                    var start = i * size;
                    var end = start + size;
                    context.beginPath();
                    context.moveTo(start, 0);
                    context.lineTo(size * i, size * maxY);
                    context.stroke();
                    context.closePath();
                }
                //繪制水平線條
                for (var i = 0; i <= maxY; i++) {
                    var start = i * size;
                    var end = start + size;
                    context.beginPath();
                    context.moveTo(0, size * i);
                    context.lineTo(size * maxX, size * i);
                    context.stroke();
                    context.closePath();
                }
            }
        </script>

    </body>

</html>

 

 本文由用戶 haiyangyiba 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!