ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

俄罗斯方块游戏-JS

2021-09-23 17:05:58  阅读:115  来源: 互联网

标签:游戏 数据源 模型 元素 JS var col 方块 row


黑马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{
            width: 200px;
            height: 360px;
            background: url("") no-repeat;
            background-size: 200px 360px;
            position: relative; 
        }

        .activity_mode{
            width: 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{
            width: 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 onl oad="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>

标签:游戏,数据源,模型,元素,JS,var,col,方块,row
来源: https://www.cnblogs.com/miaomiaowu/p/15324809.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有