zoukankan      html  css  js  c++  java
  • 俄罗斯方块游戏-JS

    黑马Bilibili

    流程

    代码

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
        <script src="https://cdn.bootcss.com/lodash.js/4.17.4/lodash.min.js"></script>
        <!-- 父容器使用 相对 位置,子容器选择 绝对 位置 -->
        <style>
            .container{
                 200px;
                height: 360px;
                background: url("") no-repeat;
                background-size: 200px 360px;
                position: relative; 
            }
    
            .activity_mode{
                 20px;
                height: 20px;
                /* background-color: cadetblue; */
                border: .3px solid #333333;
                box-sizing: border-box;
                position: absolute;
                background: #ffd75e url("") center no-repeat;
                background-size: 15px;
            }
    
    
            .fixed_mode{
                 20px;
                height: 20px;
                background-color: #fefefe;
                border: .3px solid #333;
                box-sizing: border-box;
                position: absolute;
                background: #bbbbbb url("") center no-repeat;
                background-size: 15px;
            }
        </style>
        
    </head>
    <body onload="init()">
        <!-- 背景容器 -->
        <div id ="container" class="container">
            <!-- <div class="activity_mode"></div> -->
        </div>
    
    </body>
    
    <script>
    
        // 常量
        // 每次移动的距离,步长
        var STEP = 20;
    
        // 分割容器 18行, 10列
        var ROW_COUNT = 18,
            COL_COUNT = 10;
    
        // 创建每个模型的数据源
        var MODELS = [
            // 第一个模型数据源(L型)
            /* 在4*4中画一个L型,坐标起始是0
                0 0 0 0
                0 0 1 0
                1 1 1 0
                0 0 0 0
            */
            {
                0: {
                    row: 2,
                    col: 0
                },
                1: {
                    row: 2,
                    col: 1
                },
                2: {
                    row: 2,
                    col: 2
                },
                3: {
                    row: 1,
                    col: 2
                },
            },
            // 第二个模型数据源(凸型)
            {
                0: {
                    row: 1,
                    col: 1
                },
                1: {
                    row: 0,
                    col: 0
                },
                2: {
                    row: 1,
                    col: 0
                },
                3: {
                    row: 2,
                    col: 0
                },
            },
            // 第三个模型数据源(田型)
            {
                0: {
                    row: 1,
                    col: 1
                },
                1: {
                    row: 2,
                    col: 1
                },
                2: {
                    row: 1,
                    col: 2
                },
                3: {
                    row: 2,
                    col: 2
                },
            },
            // 第四个模型数据源(一型)
            {
                0: {
                    row: 0,
                    col: 0
                },
                1: {
                    row: 0,
                    col: 1
                },
                2: {
                    row: 0,
                    col: 2
                },
                3: {
                    row: 0,
                    col: 3
                },
            },
            // 第五个模型数据源(Z型)
            {
                0: {
                    row: 1,
                    col: 1
                },
                1: {
                    row: 1,
                    col: 2
                },
                2: {
                    row: 2,
                    col: 2
                },
                3: {
                    row: 2,
                    col: 3
                },
            },
    
        ]
    
        // 变量
        // 当前使用的模型
        var currentModel = {};
        // 标记16宫格的位置
        var currentX = 0,
            currentY = 0;
        // 记录所有块元素的位置
        // K=行_列 : V=块元素
        var fixedBlocks = {};
        //定时器
        var mInterval = null;
    
        // 入口方法
        function init(){
            createModel();
            onKeyDown();
        }
    
        // 根据模型的数据源创建对应的块元素
        function createModel(){
            // 判断游戏是否结束
            if(isGameOver()){
                gameOver();
            }
            // 确定当前使用哪一个模型
            currentModel = MODELS[_.random(0, MODELS.length-1)];
            // 重新初始化 16宫格的位置
            currentX = 0;
            currentY = 0;
            // 生成对应数量的块元素
            for(var key in currentModel){
                // console.log("key: "+key);
                var divEle = document.createElement("div");
                divEle.className = "activity_mode";
                // 将模型添加到背景容器中
                document.getElementById("container").appendChild(divEle);
            }
            // 定位块元素的位置
            locationBlocks();
            // 模型自动下落
            autoDown();
        }
    
        // 根据数据源定位块元素的位置
        function locationBlocks(){
            // 判断元素越界并处理
            checkBound();
            //1. 拿到所有的块元素
            var eles = document.getElementsByClassName("activity_mode");
            
            for(var i=0; i<eles.length; i++){
                //单个块元素
                var activityModelEle = eles[i];
                //2. 找到每个块元素对应的数据
                var blockModel = currentModel[i];
                //3. 根据每个块元素对应的数据来指定块元素的位置
                //每个块元素的位置由:1)16宫格所在位置 2)块元素在16宫格中的位置 两个元素确定
                activityModelEle.style.top = (currentY + blockModel.row)*STEP + "px";
                activityModelEle.style.left = (currentX +  blockModel.col)*STEP + "px";
            }
        }
    
    
    
        // 监听用户的键盘事件
        function onKeyDown(){
            document.onkeydown = function(event){
                //console.log(event.keyCode);
                switch(event.keyCode){
                    case 37:
                        //console.log("左");
                        move(-1,0);
                        break;  
                    case 38:
                        //console.log("上");
                        rotate();
                        //move(0,-1);
                        break;
                    case 39:
                        //console.log("右");
                        move(1,0);
                        break;   
                    case 40:
                        //console.log("下");
                        move(0,1);
                        break;
                }
            }
        }
    
        // 移动
        function move(x, y){
            //控制块元素移动
            // var activityModelEle = document.getElementsByClassName("activity_mode")[0];
            // // 初始 top 为空时,取0:parseInt(activityModelEle.style.top || 0) 
            // activityModelEle.style.top = parseInt(activityModelEle.style.top || 0) + y*STEP + "px";
            // activityModelEle.style.left = parseInt(activityModelEle.style.left || 0) + x*STEP + "px";
    
            if(isMeet(currentX+x, currentY+y, currentModel)){
                // 底部的触碰发生在移动16宫格的时候,并且此次移动是因为Y轴变化引起的
                if(y !== 0){
                    // 模型之间底部发生碰撞
                    fixedBottomModel();
                }
                return;
            }
    
            //模型的移动,有16宫格的移动表示
            currentX += x;
            currentY += y;
            //根据16宫格的位置 重新定位块元素
            locationBlocks();
        }
    
        // 旋转模型
        function rotate(){
            // 旋转后的行 = 旋转前的列
            // 旋转后的列 = 3 - 旋转前的行
    
            // 克隆 currentModel
            var cloneCurrentModel = _.cloneDeep(currentModel);
    
    
            // 遍历 模型数据源
            for(var key in cloneCurrentModel){
                // 块元素的数据源
                var blockModel = cloneCurrentModel[key];
                // 实现
                var temp = blockModel.row;
                blockModel.row = blockModel.col;
                blockModel.col = 3 - temp;
            }
            //如果旋转之后发生触碰,则不允许再旋转
            if(isMeet(currentX, currentY, cloneCurrentModel)){
                return;
            }
            // 没有碰撞 接受此次旋转
            currentModel = cloneCurrentModel;
            locationBlocks();
        }
    
        // 控制模型只能在容器中移动
        function checkBound(){
            // 定义模型可以活动的边界
            var leftBound = 0,
                rightBound = COL_COUNT,
                bottomBound = ROW_COUNT;
            // 当块元素超出边界之后,让16宫格后退一步 
            for(var key in currentModel){
                // 块元素对应的数据
                var blockModel = currentModel[key];
                // 左侧越界
                if((blockModel.col + currentX) < leftBound){
                    currentX++;
                }
                // 右侧越界
                if((blockModel.col + currentX) >= rightBound){
                    currentX--;
                }
                // 底部越界
                if((blockModel.row + currentY) >= bottomBound){
                    currentY--;
                    // 把模型固定在底部
                    fixedBottomModel();
                }
            }
        }
    
        // 把模型固定在底部
        function fixedBottomModel(){
            //1. 改变模型(每个块的)的样式(可移动时是亮色,不可移动变灰)
            var activityModelEles = document.getElementsByClassName("activity_mode");
            //每次修改className后,activityModelEles 会根据当前实际的个数更新 length(4->3->2->1)
            //for(var i=0; i<activityModelEles.length; i++){ //报错 
            for(var i=activityModelEles.length-1; i>=0; i--){
                // 拿到每个块元素
                var activityModelEle = activityModelEles[i];
                // 更改块元素的类明(修改样式)
                //2. 让模型不可以再进行移动(移动时获取的是activity_mode样式)
                activityModelEle.className = "fixed_mode";
                // 把该块元素放入变量中
                var blockModel = currentModel[i];
                fixedBlocks[(currentY + blockModel.row) + "_" + (currentX + blockModel.col)]=activityModelEle;
            }
            // 判断某一行是否需要清理
            isRemoveLine();
            //3. 创建新的模型
            createModel();
        }
    
        // 判断模型之间的触碰问题
        // x, y 表示16宫格《将要》移动到的位置
        // model 表示当前模型数据源《将要》完成的变化(还没变)
        function isMeet(x, y, model){
            // 所谓模型之间的触碰,在一个固定的位置已经存在一个被固定的块元素时,那么活动中的模型不能再占用该位置
            // 判断触碰,就是再判断活动中的模型《将要移动到的位置》是否已经存在被固定的模型(块元素)
            // 如果存在返回 true,否则返回 false。
            for(var k in model){
                var blockModel = model[k];
                // 该位置是否已经存在块元素?
                if(fixedBlocks[(y+blockModel.row)+"_"+(x+blockModel.col)]){
                    return true; //表示将要移动到的位置会发生碰撞
                }
            }
            return false;
        }
    
        // 判断一行是否被铺满
        function isRemoveLine(){
            // 在一行中, 每一列都存在块元素,那么该行就需要被清理
            // 遍历所有行中的列
            // 遍历所有行
            for(var i=0; i<ROW_COUNT; i++){
                var flag = true;
                for(var j=0; j<COL_COUNT; j++){
                    // 如果当前行中有一列没有数据,那么就说明当前行没有被铺满
                    if(!fixedBlocks[i+"_"+j]){ //取不到数据
                        flag = false;
                        break;
                    }
                }
                if(flag){
                    //该行已经被铺满
                    //console.log("该行已经被铺满");
                    removeLine(i);
                }
            }
        }
    
        // 清理被铺满的这一行
        function removeLine(line){
            // 遍历该行中的所有列
            for(var i=0; i<COL_COUNT; i++){
                // 1. 删除该行中的所有的块元素
                document.getElementById("container").removeChild(fixedBlocks[line+"_"+i]);
                // 2. 删除该行中所有块元素的数据源
                fixedBlocks[line+"_"+i] = null;
            }
            downLine(line);
        }
    
        // 让被清理行之上的块元素下落
        function downLine(line){
            //遍历被清理行之上的所有行
            for(var i=line-1; i>=0; i--){
                //遍历该行中的所有列
                for(var j=0; j<COL_COUNT; j++){
                    if(!fixedBlocks[i+"_"+j]) continue; //没有元素
                    //存在数据
                    //1. 被清理行之上的所有块元素数据源所在的行数+1
                    fixedBlocks[(i+1)+"_"+j] = fixedBlocks[i+"_"+j];
                    //2. 让块元素在容器中的位置下落
                    fixedBlocks[(i+1)+"_"+j].style.top = (i+1)*STEP + "px";
                    //3. 清理掉之前的块元素
                    fixedBlocks[i+"_"+j] = null;
                }
            }
        }
    
        // 让模型自动下落
        function autoDown(){
            if(mInterval){
                clearInterval(mInterval);
            }
            mInterval = setInterval(function(){
                move(0,1)
            }, 600);
        }
    
        // 判断游戏结束
        function isGameOver(){
            // 当第0行存在块元素的时候,表示游戏结束
            for(var i=0; i<COL_COUNT; i++){
                if(fixedBlocks["0_"+i]){
                    return true;
                }
            }
            return false;
        }
    
        // 结束游戏
        function gameOver(){
            //1. 停止定时器
            if(mInterval){
                clearInterval(mInterval);
            }
            //2. 弹出对话框
            alert("Game Over!");
        }
    </script>
    </html>
    
  • 相关阅读:
    ubuntu下安装maven
    159.Longest Substring with At Most Two Distinct Characters
    156.Binary Tree Upside Down
    155.Min Stack
    154.Find Minimum in Rotated Sorted Array II
    153.Find Minimum in Rotated Sorted Array
    152.Maximum Product Subarray
    151.Reverse Words in a String
    150.Evaluate Reverse Polish Notation
    149.Max Points on a Line
  • 原文地址:https://www.cnblogs.com/miaomiaowu/p/15324809.html
Copyright © 2011-2022 走看看