俄罗斯方块 JS

游戏过程:点击开始游戏,游戏界面中有一个活动方块,准备界面有一个准备方块,都是随机生成的。所有方块的形状固定,有7种,随机生成。活动方块每次移动后都将原来位置的方块清除,记录下当前活动方块的位置再渲染颜色。活动方框每次移动都会出发边界检查。一旦碰触边界时,移动判断为合法就禁止移动了。碰触底部边界时,则落定方块,记录下当前方块的位置,在游戏界面的相同位置标记表示已经被覆盖。将当前活动方块设置为准备方块,并在游戏界面初始位置显示,准备界面清空,设置新的准备方块。当下一次移动会到游戏界面已经被覆盖的方块(值为1表示被覆盖,0为空白),为非法移动。消行就是判断游戏界面若有一行方块值全部为1,就清空该行方块。然后将该行之上的所有行逐一位置下移,每下移一行,清空上一行。游戏分数随着每个方块最后一次下移时消行的个数加倍增加。游戏状态有4种游戏,分别是未开始(0),已开始游戏(1),暂停游戏(2),游戏结束(2)。开始游戏后状态改变,定时器开始,暂停游戏后状态改变,定时器停止;继续游戏恢复开始游戏状态,定时器启动;游戏结束,状态改变,定时器为空,并恢复到位开始游戏状态,初始化游戏界面。

俄罗斯方块主要部分:

1、判断边界:判断方块移动时的横纵坐标是否大于等于游戏界面的大小,超出范围就不允许继续向该方向移动。

                        判断下一次移动的位置是否有方块覆盖,即游戏界面方块值为1。游戏界面所有方块初始值为0,表示空白。当每次落定一个方块,记录位置并赋值1,表示被覆盖。

2、旋转算法: 旋转以逆时针方向旋转90度,在数学上,俄罗斯方块是按照方块的中心点进行旋转。(x,y)是每个小方块的坐标,(x0,y0)整个方块的中心点坐标。中心点坐标是每个小方块的平均横纵坐标。方块旋转后的坐标是(x0 +y0 -y,y0-x0+x)。

3、新的活动方块和准备方块:在判断碰触底部边界后,停止定时器并更新新的活动方块和准备方块,再在页面上渲染,这就再初始位置上有新的方块了,再随其进行定时器绑定就行了

我使用的是谷歌浏览器,其他的可能有问题。关于音乐没有的看看这个,https://www.cnblogs.com/wsg25/p/9640316.html

代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        div {
            display: inline-block;
        }
        .choose {
            display: inline-block;
            position: absolute;
            left: 30%;
        }

        .game {
            position: absolute;
            width: 222px;
            height: 354px;
            left: 40%;
            display: inline-block;
        }
        .nextSquere {
            position: absolute;
            right: 33.7%;
        }
        table {
            border-color: #eee;
        }
        td {
            width: 20px;
            height: 20px;
            background-color: bisque;
        }
        #again {
            display: none;
        }
    </style>
</head>
<body>
    <audio id="sounds" loop= "loop" volume = "60">
        <source src="music.wav" id="A" type="audio/wav">
    </audio> 
    <!-- 分数和游戏控制 -->
    <div class="choose">
        score:<span class="score">0</span>
        <br>
        <br>
        <button id="begin">开始游戏</button>
        <br>
        <br>
        <button id="again">重新开始</button>
    </div>
    <!-- 游戏界面 -->
    <div class="game">
        <table class="game_content" border="1" cellpadding = 0 cellspacing = 0>
            <tr>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
            </tr>
            <tr>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
            </tr>
            <tr>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
            </tr>
            <tr>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
            </tr>
            <tr>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
            </tr>
            <tr>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
            </tr>
            <tr>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
            </tr>
            <tr>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
            </tr>
            <tr>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
            </tr>
            <tr>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
            </tr>
            <tr>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
            </tr>
            <tr>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
            </tr>
            <tr>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
            </tr>
            <tr>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
            </tr>
            <tr>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
            </tr>
            <tr>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
            </tr>
        </table>
    </div>
    <!-- 准备界面 -->
    <div class="nextSquere">
        <table class="next_content" border="1" cellpadding = 0 cellspacing = 0>
            <tr>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
            </tr>
            <tr>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
            </tr>
            <tr>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
            </tr>
            <tr>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
            </tr>
            <tr>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
            </tr>
            <tr>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
            </tr>
            <tr>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
            </tr>
            
        </table>
    </div>
    <div>
        <button id="music">音乐</button>
    </div>
    <br>
    <script>
        //游戏界面
        var game = document.getElementsByClassName("game_content")[0];
        //准备方块界面
        var nextSquere = document.getElementsByClassName("next_content")[0];
        //分数
        var score = document.getElementsByClassName("score")[0];
        //定时器,方块的下移动作moveDown()
        var timer = null;
        //开始游戏按钮会分为三种状态,未开始游戏(0),已经开始游戏(1),暂停游戏(2),结束游戏为(3)
        var status = 0;
        //重新开始按钮
        //again
        //当前正在活动的方块
        var activeBlock;
        //游戏界面的所有方块
        var table = new Array(16);
        //游戏界面中已经被方快覆盖的位置,空白为0,覆盖为1
        for(var i = 0; i < table.length; i++){
            table[i] = new Array(10);
        }
        for(var i = 0; i < table.length; i++){
            for(var j = 0; j < table[i].length; j++){
                table[i][j] = 0;  //游戏界面方块状态,初始值为0;
            }
        }
        //下一个活动的方块
        var nextBlock;
        //方块的形状,方块最宽为4,最高为4
        function shapes(){
            var block = new Array(4);
            //随机生成形状,一共有七种形状,0~6
            var r = Math.ceil(Math.random()*7) - 1;
            switch(r){
                case 0:
                    block[0] = {x:0, y:0};
                    block[1] = {x:0, y:1};
                    block[2] = {x:0, y:2};
                    block[3] = {x:0, y:3};
                    break;
                case 1:
                    block[0] = {x:0, y:1};
                    block[1] = {x:1, y:0};
                    block[2] = {x:1, y:1};
                    block[3] = {x:1, y:2};
                    break;
                case 2:
                    block[0] = {x:0, y:0};
                    block[1] = {x:1, y:0};
                    block[2] = {x:1, y:1};
                    block[3] = {x:1, y:2};
                    break;
                case 3:
                    block[0] = {x:0, y:2};
                    block[1] = {x:1, y:0};
                    block[2] = {x:1, y:1};
                    block[3] = {x:1, y:2};
                    break;
                case 4:
                    block[0] = {x:0, y:0};
                    block[1] = {x:0, y:1};
                    block[2] = {x:1, y:0};
                    block[3] = {x:1, y:1};
                    break;
                case 5:
                    block[0] = {x:0, y:1};
                    block[1] = {x:0, y:2};
                    block[2] = {x:1, y:0};
                    block[3] = {x:1, y:1};
                    break;
                case 6:
                    block[0] = {x:0, y:0};
                    block[1] = {x:0, y:1};
                    block[2] = {x:1, y:1};
                    block[3] = {x:1, y:2};
                    break;
                }
            return block;
        }
        //渲染当前活动方块的位置
        function activeLoaction(){
            for(var i = 0; i < activeBlock.length; i++){
                game.rows[activeBlock[i].x].cells[activeBlock[i].y].style.backgroundColor="yellow";
            }
        }
        //渲染准备界面方块的位置
        function nextShape(){
            for(var i = 0; i < nextBlock.length; i++){
                nextSquere.rows[nextBlock[i].x].cells[nextBlock[i].y].style.backgroundColor="yellow";
            }
        }
        //检查左边界
        function checkLeft(){
            for(var i = 0; i < activeBlock.length; i++){
                if(activeBlock[i].y === 0){
                    return false;
                }
                if(!checkGameBlock(activeBlock[i].x,activeBlock[i].y-1)){
                    return false;
                }
            }
            return true;
        }
        //检查右边界
        function checkRight(){
            for(var i = 0; i < activeBlock.length; i++){
                if(activeBlock[i].y === 9){
                    return false;
                }
                if(!checkGameBlock(activeBlock[i].x,activeBlock[i].y+1)){
                    return false;
                }
            }
            return true;
        }
        //检查下边界
        function checkBottom(){
            for(var i = 0; i < activeBlock.length; i++){
                if(activeBlock[i].x === 15){
                    return false;
                }
                if(!checkGameBlock(activeBlock[i].x+1,activeBlock[i].y)){
                    return false;
                }
            }
            return true;
        }
        //移动时,检查游戏界面中的方块是否被覆盖
        function checkGameBlock(x,y){
            if(table[x][y] == 1){
                // console.log("a");
                return false;
            }
            if(x>15||x<0||y<0||y>9){
                return false;
            }
            return true;
        } 
        //判断最初位置能否放方块
        function initLocation(){
            for(var i = 0; i < 4; i++){
                if(table[nextBlock[i].x][nextBlock[i].y] == 1){
                    gameOver();
                }
            }
        }
        //向左移动
        function moveLeft(){
            if(checkLeft()){
                clearActive();
                //移动方块位置
                for(var i = 0 ; i < activeBlock.length; i++){
                    activeBlock[i].y -= 1;
                }
                activeLoaction();
            }
        }
        //向右移动
        function moveRight(){
            if(checkRight()){
                clearActive();
                //移动方块位置
                for(var i = 0 ; i < activeBlock.length; i++){
                    activeBlock[i].y += 1;
                }
                activeLoaction();
            }
        }
        //向下移动
        function moveDown(){
            //console.log(checkBottom());
            //没碰到底部边界,继续运动
            if(checkBottom()){
                clearActive();
                //移动方块位置
                for(var i = 0 ; i < activeBlock.length; i++){
                    activeBlock[i].x += 1;
                }
                activeLoaction();
            }
            //碰到底部边界就停止所有可能的动作
            else {
                //停止向下移动的定时器
                clearInterval(timer);
                //记住当前游戏界面的方块已落下的方块位置
                remember(activeBlock);
                //判断最初位置能否放方块
                initLocation();
                if(status == 1){
                    //消行
                    var rows = clearRow();
                    //更新分数
                    if(rows != 0){     
                        //一次消多行则分数加倍  
                        switch(rows) {
                            case 1:
                                score.innerHTML = parseInt(score.innerHTML) + rows*10;
                                break;
                            case 2:
                                score.innerHTML = parseInt(score.innerHTML) + rows*10*2;
                                break;
                            case 3:
                                score.innerHTML = parseInt(score.innerHTML) + rows*10*3;
                                break;
                            case 4:
                                score.innerHTML = parseInt(score.innerHTML) + rows*10*4;
                                break;
                        }
                    }
                    //更新当前活动方块为准备方块
                    activeBlock = nextBlock;  
                    activeLoaction();
                    //消除准备界面方块
                    clearNext();                
                    //更新准备方块
                    nextBlock = shapes(); 
                    //更新准备方块界面
                    nextShape();
                    //定时器, 每隔一秒执行一次moveDown 
                    timer = setInterval(moveDown,1000)
                }else if(status == 2){
                    // stopGame();
                }else if(status == 3){
                    return;
                }
            }
        }
        //旋转方块
        function rotate(){
            var rotateBlock = copyBlock(activeBlock);
            var centerX = 0;
            var centerY = 0;
            //算法思想:坐标(x,y)绕中心点(x0,y0)逆时针旋转90度后的坐标为(x0+y0-y,y0-x0+x)
            for(var i = 0; i < rotateBlock.length; i++){
                centerX += rotateBlock[i].x;
                centerY += rotateBlock[i].y;
                //求中心点坐标
                if(i == 3){
                    centerX = Math.round(centerX / 4);
                    centerY = Math.round(centerY / 4);
                }
            }
            //旋转后坐标,这里注意,是当前活动方块的中心点,不是拷贝的旋转方块的中心点
            for(var i = 0; i < 4; i++){
                rotateBlock[i].x = centerX + centerY - activeBlock[i].y;
                rotateBlock[i].y = centerY - centerX + activeBlock[i].x;
            }
            //先判断是否合法
            for(var i = 0; i < 4; i++){
                if(!checkGameBlock(rotateBlock[i].x,rotateBlock[i].y)){
                    return;
                }
            }
            //合法就清除变换前方块
            clearActive();
            //更新当前活动方块形状
            for(var i=0; i<4; i++){    
                activeBlock[i].x = rotateBlock[i].x;    
                activeBlock[i].y = rotateBlock[i].y;    
            }   
            activeLoaction();
        }
        //记住游戏界面每次确定落完的方块位置,不能被覆盖和碰触
        function remember(fallBlock){
            // console.log(fallBlock);
            for(var k = 0; k < 4; k++){
                table[fallBlock[k].x][fallBlock[k].y] = 1;
            }
            // for(var i = 0; i < table.length; i++){
            //     for(var j = 0; j < table[i].length; j++){
            //         console.log(table[i][j]);  //检查游戏界面方块状态,初始值为0;
            //     }
            // }
        }
        //初始化界面
        function init(){
            clearInterval(timer);
            score.innerHTML = 0;
            begin.innerHTML = '开始游戏';
            clearGame();
            clearNext();
            for(var i = 0; i < table.length; i++){
                for(var j = 0; j < table[i].length; j++){
                    table[i][j] = 0;
                }
            }
            timer = null;
            status = 0;
        }
        //消除游戏界面每次移动前的方块
        function clearActive(){
            for(var i=0; i<4; i++){    
                game.rows[activeBlock[i].x].cells[activeBlock[i].y].style.backgroundColor="bisque";
            } 
        }
        //消除准备方块界面的方块
        function clearNext(){
            for(var i = 0; i < 4; i++){      
                nextSquere.rows[nextBlock[i].x].cells[nextBlock[i].y].style.backgroundColor="bisque";
            } 
        }
        //消除游戏界面所有方块
        function clearGame(){   
            for(var i = 0; i< table.length; i++){   
                for(var j = 0; j < table[i].length; j++){   
                    game.rows[i].cells[j].style.backgroundColor = "bisque";   
                }   
            }   
        }
        //消行
        function clearRow(){
            var row = 0;
            for(var i = 0; i < table.length; i++){
                var flag = true;
                for(var j = 0; j < table[i].length; j++){
                    if(table[i][j] == 0){
                        flag = false;
                        break;
                    }
                }
                if(flag){
                    row++;
                    for(var k = table[i].length - 1; k >= 0; k--){
                        table[i][k] = 0;
                        game.rows[i].cells[k].style.backgroundColor = "bisque";  
                    }
                    //更新消行后的游戏界面方块位置
                    for(var q = i; q >= 1; q--){
                        for(var p = 0; p < table[q].length; p++){
                            table[q][p] = table[q - 1][p];
                            table[q-1][p] = 0;
                            game.rows[q-1].cells[p].style.backgroundColor = "bisque";
                        }
                    }
                }
            }
            //更新后给方块加颜色
            for(var i = 0; i < table.length; i++){
                for(var j = 0; j < table[i].length; j++){
                    if(table[i][j] == 1){
                        game.rows[i].cells[j].style.backgroundColor = "yellow";
                    }
                }
            }
            // console.log(row);
            return row;
        }
        //更新分数
        function updateScore(i){
            score = 10*i + parseInt(score.innerHTML);
            score.innerHTML = score;
        }
        //键盘上下左右代表旋转,向下,向左,向右移动
        document.onkeydown = function(){
            if(status == 1) {
                if(event.keyCode == 37){
                    moveLeft();
                }else if(event.keyCode == 38){
                    rotate();
                }else if(event.keyCode == 39){
                    moveRight();
                }else if(event.keyCode == 40){
                    moveDown();
                }
            }
        }
        //复制一个活动方块
        function copyBlock(b) {
            var o = new Array(4);
            for(var i = 0; i < o.length; i++){
                o[i] = {x:0, y:0};
            }
            for(var i=0; i<4; i++){    
                o[i].x = b[i].x;    
                o[i].y = b[i].y;    
            }  
            return o;  
        }
        //点击游戏开始,开始游戏按钮会分为三种状态,开始游戏,暂停游戏,继续游戏
        begin.onclick = function(){
            again.style.display = 'inline';
            if(begin.innerHTML == '开始游戏') {
                start();
                begin.innerHTML = '暂停游戏';
            }else if(begin.innerHTML == '暂停游戏'){
                stopGame();
                begin.innerHTML ='继续游戏';
            }else if(begin.innerHTML == '继续游戏'){
                continueGame();
                begin.innerHTML = '暂停游戏';
            }
        }
        //重新开始游戏事件
        again.onclick = function(){
            sounds.load();
            init();
            start();
            begin.innerHTML = '暂停游戏';
        }
        //开始游戏
        function start(){
            sounds.play();
            status = 1;
            activeBlock = shapes(); 
            activeLoaction(); 
            nextBlock = shapes();
            nextShape();
            timer = setInterval(moveDown,1000);
        }
        //暂停游戏
        function stopGame(){
            status = 2;
            sounds.pause();
            clearInterval(timer);
        }
        //继续游戏
        function continueGame(){
            status = 1;
            sounds.play();
            timer = setInterval(moveDown,1000);
        }
        //游戏结束
        function gameOver(){
            sounds.pause();
            status = 3;
            alert("Game Over,你的分数是"+score.innerHTML+"分,请继续努力");
            init();
        }
    </script>
</body>
</html>

 

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值