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>
    
  • 相关阅读:
    你的内存不够啦:c++: internal compiler error: Killed (program cc1plus)
    ARM交叉编译器GNUEABI、NONE-EABI、ARM-EABI、GNUEABIHF等的区别
    arm-linux-gnueabihf、aarch64-linux-gnu等ARM交叉编译GCC的区别
    ubuntu与centos的对比和选择
    Deep Convolutional Network Cascade for Facial Point Detection实践总结
    深度学习(十七)基于改进Coarse-to-fine CNN网络的人脸特征点定位
    《Deep Convolutional Network Cascade for Facial Point Detection》复现
    使用axis2,根据WSDL生成java客户端代码
    oracle字段NCHAR查询,
    【转】fastdfs第一次上传文档报错recv package size
  • 原文地址:https://www.cnblogs.com/miaomiaowu/p/15324809.html
Copyright © 2011-2022 走看看