俄罗斯方块完整代码

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Russian Block</title>
    <link rel="stylesheet" href="./css/index.css">
</head>
<body>
    <!--游戏活动区域-->
<article class="container" id="container">
    <!--开始游戏按钮-->
       
    <button id="start">开始游戏</button>
    </article>
    
    <script src="./js/index.js"></script>
    <script src="./js/jquery-3.5.1.min.js"></script>
</body>
</html>

index.css

/* 初始化页面样式 */
* {
    margin: 0;
    padding: 0;
    list-style: none;
}

/* 设置活动区域container样式 */
.container {
    width: 540px;
    height: 600px;
    background-color: black;
    margin: 30px auto 0;
    position: relative;
}

/*设置游戏活动区域创建块元素 actvity_model 样式*/
.actvity_model{
    background-color: cadetblue;
    border: 1px solid #eee;
    box-sizing: border-box;
    position: absolute;
}

/*按钮样式*/
#start{
    top: -27px;
    right: 1px;
    position: absolute;
    color: #fff;
    width: 100px;
    border: 1px solid cadetblue;
    background-color: cadetblue;
    height: 26px;
    text-align: center;
}

/*滑到底部固定游戏快*/
.fixed_model {
    background-color: #FFF;
    border: 1px solid #333;
    box-sizing: border-box;
    position: absolute;
}

/* 提示框 */
#model{
    margin: auto;
    width: 200px;
    border: 3px solid cadetblue;
    padding: 30px 10px;
    position: fixed;
    margin-left: -122px;
    margin-top: -262px;
    text-align: center;
    left: 50%;
    top: 50%;
    background: #fff;
    display: none;
}

index.js

function CreateRandomModel(){
     // 创建所有可能的方块的数组
     var MODELS = [
            {//第一个 L 字型
                 'name': 'L 字型',
                 'model': [[0,0],[1,0],[2,0],[2,1]]
            },
            {//第二个 J 字型
                 'name': 'J 字型',
                 'model': [[0,1],[1,1],[2,0],[2,1]]
            },
            {//第三个凸字型
                 'name': '凸字型',
                 'model': [[1,1],[0,0],[1,0],[2,0]]
            },
            {//第四个田字型
                 'name': '田字型',
                 'model': [[0,0],[0,1],[1,0],[1,1]]
            },
            {//第五个一字型
                 'name': '一字型',
                 'model': [[0,0],[0,1],[0,2],[0,3]]
            },
            {//第六个 Z 字型
                 'name': 'Z 字型',
                 'model': [[0,0],[0,1],[1,1],[1,2]]
            }
     ];
 
     // 随机方块模型下标
     var ramdomNum = Math.floor(Math.random()*MODELS.length);
 
     //方块模型名称
     this.name = MODELS[ramdomNum]['name'];
 
     //方块模型
     this.blockModel = MODELS[ramdomNum]['model'];
 }
 
 CreateRandomModel.prototype.getBlockModle = function(){
     return this.blockModel;
 }
 
 CreateRandomModel.prototype.getName = function(){
     return this.name;
 }
 
 // 显示屏的高度
 var screenWidth = window.screen.width;
 var screenHeight = window.screen.height;
 console.log(screenWidth);
 console.log(screenHeight);
 
 // 根据屏幕分辨率设置步长
 var STEP;
 if(screenWidth >= 1200){
      STEP = 30;
 }else if(screenWidth >= 992){
      STEP = 20;
 }else if(screenWidth >= 768){
      STEP = 10;
 }else{
      STEP = 5;
 }
 
 // 根据步长得到方块的宽高
 var boxWidth = STEP;
 var boxHeight = STEP;
 // 根据游戏界面方块的行列数得到游戏界面的宽高
 var gameHeight = STEP*20;
 var gameWidth = STEP*18;
 console.log(gameWidth);
 console.log(gameHeight);
 console.log(boxWidth);
 console.log(boxHeight);
 
 // 分割容器为多少行多少列(即多少个单个方块的距离)
 var W_COUNT=gameWidth/boxWidth;
 var H_COUNT=gameHeight/boxHeight;
 
 //定义变量设置当前使用的模型
 var currentModel = [];
 //标记初始位置
 var currentX = 0;
 var currentY = 0;
 
 //根据模型的数据创建对应的块元素
 function createModel() {
     //判断游戏是否结束
     if(isGameOver()){
          // console.log("游戏结束!")
     gameOver();
          return;
     }
      //游戏界面宽高样式设置
      document.getElementById('container').style.width = gameWidth + 'px';
      document.getElementById('container').style.height = gameHeight + 'px';
 
      //调用构造函数,实例化一个随机方块对象
      var objectBlocks = new CreateRandomModel();
      //获取随机方块对象的模型
      currentModel = objectBlocks.getBlockModle();
      //重新初始化 16 宫格位置
      currentX = 0;
      currentY = 0;
 
      for (var key in currentModel) {
           //创建 div 子节点
           var divEle = document.createElement('div');
           //给 div 子节点设置 class 属性值
           divEle.className = 'actvity_model';
           //追加方块到游戏界面中
           document.getElementById('container').appendChild(divEle);
           //方块模型中单个方块宽高样式设置
           document.getElementsByClassName('actvity_model')[key].style.width = boxWidth + 'px';
           document.getElementsByClassName('actvity_model')[key].style.height = boxHeight + 'px';
      }
 }
 
 //根据数据源定义移动块元素的位置
 function locationBlocks(){
      //方块移动时需要判断活动边界,在函数顶部调用
      checkBound();
      //获取所有的块元素
      var eles = document.getElementsByClassName('actvity_model');
      for (var i=0; i<eles.length; i++){
           //单个块元素
           var actityModelEle = eles[i];
           //找到每个块元素对应的数据(行,列)
           var blockModel = currentModel[i];
           //根据每个块元素对应的数据来指定块元素的位置
           //每个块元素的位置由两个值来决定 (16 宫格所在的位置/块元素在 16 宫格的位置)(每次移动的距离,为单个方块的宽高度)
           actityModelEle.style.top = (currentY + blockModel[0]) * boxWidth + 'px';
           actityModelEle.style.left = (currentX + blockModel[1]) * boxHeight + "px";
      } 
 }
 //点击页面中“开始游戏”按钮,触发点击事件后游戏开始
document.getElementById('start').onclick=function(){
     //清除已有模态框元素
     $("#modal").remove();
     //获取根据模型的数据创建对应的块元素
     createModel();
     //根据数据源定义移动块元素的位置
     locationBlocks();
     //监听用户的键盘事件()
     onKeyDown();
}

//创建 onKeyDown()函数监听用户的键盘事件
function onKeyDown(){
     document.onkeydown = function(event){
          console.log(event.keyCode)
     }
}

//监听用户的键盘事件
function onKeyDown() {
     //获取按下的键盘按键 Unicode 值
     document.onkeydown = function (event) {
          switch (event.keyCode) {
               case 38: //(上方向键)
                    console.log("上键")
                    rotate();
                    break;
               case 39: //(右方向键)
                    console.log("右键")
                    move(1,0);
                    break;
               case 40: //(下方向建)
                    console.log("下键")
                    move(0,1);
                    break;
               case 37: //(左方向建)
                    console.log("左键")
                    move(-1,0);
                    break;
          }
     }
}

//移动
function move(x, y) {
     if (isMent(currentX + x, currentY + y, currentModel)) {
          if (y !== 0) {
               // console.log("发生了触碰");
               //模型之间底部发生了触碰
               fixedBottonModel();
          }
     }
          
     //16 宫格移动
     currentX += x;
     currentY += y;
     //根据 16 宫格的位置重新定位块元素
     locationBlocks();
}

// 旋转模型
function rotate() {
     var cloneModels = deepClone(currentModel);
     //测试代码
     console.log(cloneModels);
     //遍历模型数据源
     for (var key in currentModel) {
          //块元素数据源
          var blockModel = currentModel[key];
          var temp = blockModel[0]
          //旋转前的行=旋转后的列
          blockModel[0] = blockModel[1];
          //旋转后的行=3-旋转前的行
          blockModel[1] = 3 - temp;
     }
     if(isMent(currentX, currentY, cloneModels)) {
          return;
     }
     //重新定位块元素
     locationBlocks();
}

function checkBound() {
     //定义模型可以活动边界
     var leftBound = 0;
     var rightBound = W_COUNT;
     var boottonBound = H_COUNT;
     //当块元素超出了边界后,让 16 宫格后退
     for (var key in currentModel) {
          var blockModel = currentModel[key];
          //左侧越界
          if ((blockModel[1] + currentX) < leftBound ) {
               currentX++;
          }
          //右侧越界
          if ((blockModel[1] + currentX) >= rightBound) {
               currentX--;
          }
          // 底部越界
          if ((blockModel[0] + currentY) >= boottonBound) {
               currentY--;
               //把模型固定在底部
               fixedBottonModel();
          }
     }
}

// 记录所有块元素的位置
var fixedBlocks = [];

function reStore(){
     //遍历行
     for(var i=0;i<=H_COUNT;i++){
          fixedBlocks[i] = [];
     //遍历列
     for(var j=0;j<=W_COUNT;j++){
          fixedBlocks[i][j] = null;
          }
     }
}



function fixedBottonModel() {
     var activityModelEles = $(".actvity_model");
     //遍历获取的类元素
     for(var i = activityModelEles.length - 1; i >= 0; i--) {
     //获取当前的模型     
          var activityModelEle = activityModelEles[i];
          //更改块元素的类名     
          $(activityModelEle).attr("class","fixed_model");
          var blockModel = currentModel[i];
          //把该元素放入变量中
          fixedBlocks[currentY + blockModel[0]][currentX + blockModel[1]] =activityModelEle;
     }
     //判断是否清理
     isRemoveLine();
     //创建新的模型
     createModel();
}
//判断是否碰撞
function isMent(x, y, model) {
     for (var k in model) {
          var blockModel = model[k];
          //先判断一维数组是否存在元素
          if(!fixedBlocks[y + blockModel[0]]) {
               return true;
          }
          //再判断二维数组里面是否存在元素
          if (fixedBlocks[y +blockModel[0]][x + blockModel[1]]) {
               return true;
          }
     }
     return false;
}

function deepClone(obj) {
     var _obj = JSON.stringify(obj), 
     cloneObj = JSON.parse(_obj);
     return cloneObj;
}

function isRemoveLine() {
     // 遍历所有行中的列
     for (var i = 0; i < H_COUNT; i++) {
         // 标记符,假设当前行被铺满
         var flag = true;
         // 遍历当前行中的所有列
         for (var j = 0; j < W_COUNT; j++) {
             // 如果当前行中有一列没有数据那就说明没有被铺满
             if (!fixedBlocks[i] || !fixedBlocks[i][j]) {
                 flag = false;
                 break;
             }
         }
         if (flag) {
             // 该行已经被铺满
             // console.log("该行已经被铺满");
             // 清理被铺满的该行
             removeLine(i);
         }
     }
     // 判断 flag 值是否为 true
     if (flag) {
         // 该行已经被铺满
         console.log("该行已经被铺满");
     }
 }
 
 
 function removeLine(line) {
     //遍历该行中的所有行
     for (var i = 0; i < W_COUNT; i++) {
         //删除该行中的所有块元素
         if(!fixedBlocks[line]) fixedBlocks[line] = [];
         $(fixedBlocks[line][i]).remove();
         //删除该行中的所有块元素的数据源
         fixedBlocks[line][i] = null;
     }
     downLine(line);
     }
 
 
 function downLine(line) {
     //遍历被清理行之上的所有行
     for (var i = line - 1; i >= 0; i--) {
     //该行中所有列
         for (var j = 0; j < H_COUNT; j++) {
             if(!fixedBlocks[i]) fixedBlocks[i] = [];
             //假如不存在
             if (!fixedBlocks[i][j]) continue;
             //存在数据
             //1.被清理行之上的所有块元素数据源所在的行数+1
             if(!fixedBlocks[i+1]) fixedBlocks[i+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 isGameOver(){
     //当第0行存在元素的时候,表示游戏结束
     for (var i =0;i<W_COUNT;i++){
          if(fixedBlocks[0][i]||fixedBlocks[1][0]||fixedBlocks[1][1]||fixedBlocks[1][2]||fixedBlocks[1][3]){
               return true;
          }
     }
     return false;
}

function gameOver(){
     if ($("#model").length <= 0){ //校验页面是否存在提示框元素
          var model = $('#container').append("<div id='model'<p>本轮游戏结束!</p></div>");
     }
     //淡入效果显示提示框
     $('#model').fadeIn(100);
     $('.fixed_model').remove();
}
 
 //点击游戏界面,触发点击事件后游戏开始
 document.getElementById("start").onclick = function () {
     reStore();
     //获取根据模型的数据创建对应的块元素
     createModel();
     //根据数据源定义移动块元素的位置
     locationBlocks();
     //监听用户的键盘事件()
     onKeyDown();
 }

 

关于jQury的相关功能

第一步:打开 index.html 文件,在页面引入 jquery 文件。
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Russian Block</title>
    <link rel="stylesheet" href="./css/index.css">
</head>
<body>
    <!--游戏活动区域-->
<article class="container" id="container">
    <!--开始游戏按钮-->
    
    
    <button id="start">开始游戏</button>
    </article>
    

    <script src="./js/index.js"></script>
    <script src="./js/jquery-3.5.1.min.js"></script>
</body>
</html>
 第二步:在 index.js 文件中,创建 fixedBottonModel() 函数,固定模型。

  • 使用 jQuery 的 $(“.actvity_model”) 获取页面中所有类名为 “actvity_model” 的元素,并保存在 activityModelEles 变量中。

  • 在 fixedBottonModel 函数中遍历获取的类元素,获取当前遍历元素,使用 jQuery 操 作 DOM 属性,更改元素属性值。

  • 获取当前方块坐标(currentX 和 currentY),根据方块模型 currentModel 中每个方块的相对坐标,计算出它们在 fixedBlocks 数组中的绝对坐标,并将对应的 activityModelEle 元素保存在 fixedBlocks 数组中,以便于后续处理。

  • 调用 isRemoveLine() 函数判断是否需要清除行。

  • 最后调用 createModel() 函数创建新的模型。

 第三步:在 index.js 文件中,创建 isMent() 函数,判断模型之间是否有触碰。

  • 函数名为 isMent,接收三个参数:x、y 和 model。这三个参数表示方块的当前位置和方块模型。
  • 使用 for…in 循环遍历方块模型 model。在循环中,将当前方块的相对位置保存在变量 blockModel 中。
  • 首先,判断一维数组 fixedBlocks 中的第 y + blockModel[0] 个元素是否存在,即判断方块下方是否有其他方块。如果不存在,说明方块碰撞,返回 true。其次,判断二维数组 fixedBlocks 中的第 y + blockModel[0] 行、第 x + blockModel[1] 列的元素是否存在,即判断方块的当前位置是否有其他方块。如果存在,说明方块碰撞,返回 true。

  • 如果以上两个判断都没有返回 true,说明方块未发生碰撞,继续遍历下一个方块。如果遍历完所有方块后仍然没有返回 true,说明方块与其他方块没有发生碰撞,返回 false。

在 move() 函数顶部调用 isMent() ,如果当前存在模型之间发生触碰,并且模型 坐标在底部,使用 console.log 测试是否成功。

修改调试代码,调用 fixedBottonModel() 固定模型,终止函数执行

 第四步:在 index.js 文件中,定义 deepClone(obj)函数,编辑 rotate()函数,设置方块 旋转后触碰。
  • 函数名为 deepClone,接收一个参数 obj,表示待拷贝的对象。
  • 在函数内部,将待拷贝的对象 obj 使用 JSON.stringify 方法转换为字符串形式,并将结果保存在 _obj 变量中。
  • 然后,使用 JSON.parse 方法将 _obj 字符串解析成一个新的对象,并将其保存在 cloneObj 变量中。
  • 最后,返回 cloneObj,即完成了深拷贝操作。

在 rotate() 函数中实例化 deepClone()

在 rotate() 函数中使用深拷贝过来的数据源 cloneModels 替换原有的数据 currentModel 。调用 isMent() 函数设置参数为当前坐标 currentX , currentY ,克隆 数据源 cloneModels 。

第五步:在 index.js 文件中,创建 isRemoveLine() 函数,判断一行是否被铺满。
  1. 使用循环遍历游戏区域的行。这里使用的是变量 i,它从0开始逐渐增加,直到达到行数的上限 H_COUNT。在每一次循环中,代码会设置一个标记变量 flag,将其初始值设为 true。这个标记变量用于记录当前行是否被填满。

  2. 在嵌套的循环中,代码遍历当前行的所有列。同样,这里使用的是变量 j,它从0开始逐渐增加,直到达到列数的上限 W_COUNT。在每一次列的循环中,代码会检查当前行中的每一列是否有方块。这里通过判断 fixedBlocks[i][j]是否存在来确定当前列是否有方块。如果当前列没有方块,则说明当前行没有被填满,此时将 flag 设置为 false

  3. 如果在列的循环中发现当前行没有被填满(即 flag 为 false),则会跳出内部循环,并继续处理下一行的判断。如果在列的循环结束后,标记变量 flag 仍然为 true,则说明当前行被填满。这时,代码调用函数 removeLine(i) 来移除该行并执行相应的操作。函数 removeLine 的实现在代码中并未给出。

  4. 循环继续,处理下一行的判断和操作。循环结束后,代码会再次判断标记变量 flag 的值。如果 flag 仍然为 true,则输出 “该行已经被铺满” 的消息。

在 fixedBottonModel()方法中调用 isRemoveLine()方法

 

 

第六步:在 index.js 文件中,创建 removeLine() 函数,清理被铺满的一行。 

定义removeLine()函数,获取行号“i”,遍历该行中的所有列数,它从0开始逐渐增加,直到达到列数的上限 W_COUNT

在每次循环中,代码首先检查被删除行 line 是否存在于 fixedBlocks 数组中。

然后,代码使用 $(fixedBlocks[line][i]).remove() 将该行中的方块元素从DOM中删除。这里使用了 $ 函数,可能是为了使用jQuery库的选择器来删除对应的DOM元素。

同时,代码将被删除行 line 中的方块元素在 fixedBlocks 数组中的对应位置设置为 null,从而清除了方块元素的数据源。

第七步: 在 index.js 文件中,创建 downLine() 函数,让被清理行之上的块元素下 落。

遍历被清理行之上的所有行,遍历该行所有列,判断当前是否存在数据,如果存在数据。 

 使用遍历序号访问二维数组 fixedBlocks 中元 素,判断当前元素是否存在,如果不存在在被清理行之上的所有块元素数据源所在的行数 line+1。将方块元素的数据源复制到新的位置。将方块元素在容器中的位置向下移动一个单位,清空原来位置的方块元素的数据源,即 fixedBlocks[i][j] = null

设置该元素中的 css 样式,让块元素在容器中的位置下落

 

第八步:在 index.js 文件中,创建判断游戏结束的函数 isGameOver()。 

(1)创建 isGameOver()函数,使用 for 循环遍历列数组,判断二维数组 fixedBlocks 第 0 行是否存在块元素,如果 存在表示游戏结束,返回 true。如果不存在元素,则返回 false 表示游戏还未结束。

(2)在生成模型 createModel 前判断游戏是否结束(isGameOver()返回 true),如果游戏结束,终止函数,

 

第九步:游戏结束,创建 gameOver()函数,生成游戏结束提示模态框 

在 index.css 文件中设置 id 为#modal 模态框的样式,设置为垂直居中浮动在页面 中间,默认为隐藏状态。

 

在 index.js 文件中,创建 gameOver()函数。校验页面是否存在模态框元素,如果 不存在使用 jQuery Dom 操作在页面游戏区添加模态框。使用 jQuery 动画显示隐藏的提示框 元素,并删除游戏区中方块元素。

 

当 isGameOver()返回 true 表示游戏结束,调用 gameOver()函数,并终止创建模块 函数 createModel 运行。

 

在 index.js 文件中,在开始游戏点击事件时使用 jQuery Dom 操作清除掉页面中的 模态框元素。

 

运行此代码

开始游戏:

 

猜你喜欢

转载自blog.csdn.net/2201_76041915/article/details/135005209