zoukankan      html  css  js  c++  java
  • JS实现——俄罗斯方块

    把以下代码保存成Tetris.html文件,使用Google或360浏览器打开

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 4.0 Transitional//EN">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
      <meta name="charset-8"/>
      <title> new document </title>
    </head>
    
    <body>
      <div id="space"></div>
      <div id="debug" style="position:relative;top:-600px;left:330px"></div>
    </body>
    
    <script>
    //定义按键
    var KEY_LEFT = 37;
    var KEY_RIGHT = 39;
    var KEY_ROTATE = 38;
    var KEY_ACCELERATE = 40;
    var KEY_PAUSE = 13;
    var KEY_ONE_STOP = 32;
    
    //定义地图大小
    var MAP_R = 18;
    var MAP_C = 10;
    
    //定义方块大小
    var BLOCK_R = 4;
    var BLOCK_C = 4;
    //定义各种方块
    var BLOCKS = [
    //I
    [
     [[1,1,1,1], 
      [0,0,0,0],
      [0,0,0,0],
      [0,0,0,0]],
     [[0,1,0,0], 
      [0,1,0,0],
      [0,1,0,0],
      [0,1,0,0]],
     [[1,1,1,1], 
      [0,0,0,0],
      [0,0,0,0],
      [0,0,0,0]],
     [[0,1,0,0], 
      [0,1,0,0],
      [0,1,0,0],
      [0,1,0,0]]
    ],
    
    //L
    [
     [[1,0,0,0], 
      [1,1,1,0],
      [0,0,0,0],
      [0,0,0,0]],
     [[1,1,0,0], 
      [1,0,0,0],
      [1,0,0,0],
      [0,0,0,0]],
     [[1,1,1,0], 
      [0,0,1,0],
      [0,0,0,0],
      [0,0,0,0]],
     [[1,0,0,0], 
      [1,0,0,0],
      [1,1,0,0],
      [0,0,0,0]]
    ],
    
    //J
    [
     [[1,1,1,0],
      [1,0,0,0],
      [0,0,0,0],
      [0,0,0,0]],
     [[1,1,0,0],
      [0,1,0,0],
      [0,1,0,0],
      [0,0,0,0]],
     [[0,0,1,0],
      [1,1,1,0],
      [0,0,0,0],
      [0,0,0,0]],
     [[1,0,0,0],
      [1,0,0,0],
      [1,1,0,0],
      [0,0,0,0]]
    ],
    
    //O
    [
     [[0,1,1,0], 
      [0,1,1,0],
      [0,0,0,0],
      [0,0,0,0]],
     [[0,1,1,0], 
      [0,1,1,0],
      [0,0,0,0],
      [0,0,0,0]],
     [[0,1,1,0], 
      [0,1,1,0],
      [0,0,0,0],
      [0,0,0,0]],
     [[0,1,1,0], 
      [0,1,1,0],
      [0,0,0,0],
      [0,0,0,0]]
    ],
    
    //S
    [
     [[0,1,1,0],
      [1,1,0,0],
      [0,0,0,0],
      [0,0,0,0]],
     [[0,1,0,0],
      [0,1,1,0],
      [0,0,1,0],
      [0,0,0,0]],
     [[0,1,1,0],
      [1,1,0,0],
      [0,0,0,0],
      [0,0,0,0]],
     [[0,1,0,0],
      [0,1,1,0],
      [0,0,1,0],
      [0,0,0,0]]
    ],
    
    //T
    [
     [[0,1,0,0],
      [1,1,1,0],
      [0,0,0,0],
      [0,0,0,0]],
     [[0,1,0,0],
      [0,1,1,0],
      [0,1,0,0],
      [0,0,0,0]],
     [[0,0,0,0],
      [1,1,1,0],
      [0,1,0,0],
      [0,0,0,0]],
     [[0,1,0,0],
      [1,1,0,0],
      [0,1,0,0],
      [0,0,0,0]]
    ],
    
    //Z
    [
     [[1,1,0,0],
      [0,1,1,0],
      [0,0,0,0],
      [0,0,0,0]],
     [[0,1,0,0],
      [1,1,0,0],
      [1,0,0,0],
      [0,0,0,0]],
     [[1,1,0,0],
      [0,1,1,0],
      [0,0,0,0],
      [0,0,0,0]],
     [[0,1,0,0],
      [1,1,0,0],
      [1,0,0,0],
      [0,0,0,0]]
    ]
    ];
    
    var map = [];
    for(var r = 0; r < MAP_R; r++) {
      map.push([]);
      for(var c = 0; c < MAP_C; c++) {
        map[r][c] = {};
        map[r][c].b = 0;
      }
    }
    
    var colors = ['darkorange','darkviolet','mediumblue','red','lightseagreen','yellow','lime'];
    
    var enableShadow = true;
    var shadow = {};
    
    var currR, currC; //方格当前在Space的左顶点位置
    var currType; //当前正在落下方块的种类
    var currDir = 0; //当前正在落下方块的方向
    var pause = false;
    
    //可以落下
    function canFall(currR, currC) {
      for(var c = 0; c < BLOCK_C; c++)
        for(var r = BLOCK_R - 1; r >= 0; r--) {
          if(!BLOCKS[currType][currDir][r][c])
            continue;
          if(currR + r + 1 > MAP_R - 1)
            return false;
          if(map[currR + r + 1][currC + c].b)
            return false;
       }
      return true;
    }
    
    //找方块的投影坐标
    function makeShadow() {
      shadow.r = currR;
      shadow.c = currC;
      while(canFall(shadow.r, shadow.c)) {
        shadow.r++;
      }
    }
    
    //落下状态设置到map
    function fall(block) {
      for(var r = 0; r < BLOCK_R; r++)
        for(var c = 0; c < BLOCK_C; c++)
          if(BLOCKS[currType][currDir][r][c]) {
            map[currR + r][currC + c].b = BLOCKS[currType][currDir][r][c];
            map[currR + r][currC + c].c = currType;
          }
    }
    
    //可以左移
    function canLeft() {
      for(var r = 0; r < BLOCK_R; r++)
        for(var c = 0; c < BLOCK_C; c++) {
          if(!BLOCKS[currType][currDir][r][c])
            continue;
          if(currC + c - 1 < 0)
            return false;
          if(map[currR + r][currC + c - 1].b)
            return false;
       }
      return true;
    }
    
    //可以右移
    function canRight() {
      for(var r = 0; r < BLOCK_R; r++)
        for(var c = BLOCK_C - 1; c >= 0; c--) {
          if(!BLOCKS[currType][currDir][r][c])
            continue;
          if(currC + c + 1 > MAP_C - 1)
            return false;
          if(map[currR + r][currC + c + 1].b)
            return false;
       }
      return true;
    }
    
    //可以旋转
    function canRotate() {
      return true;
    }
    
    //获得满行的行位置
    function checkFullRows() {
      var rows = [];
      var full;
      for(var r = currR; r < MAP_R; r++) {
        full = true;
        for(var c = 0; full && c < MAP_C; c++)
          full = map[r][c].b;
        if(full)
          rows.push(r);
      }
      return rows;
    }
    
    function showPop(rows) {
      for(var i = 0; i < rows.length; i++)
        for(var c = 0; c < MAP_C; c++)
          $(rows[i] + '-' + c).style.backgroundColor = 'transparent';
    }
    
    //在map消除指定行位置的行
    function popRows(rows) {
      for(var i = 0; i < rows.length; i++)
        for(var r = rows[i] - 1; r >= 0; r--)
          for(var c = 0; c < MAP_C; c++) {
            map[r + 1][c].b = map[r][c].b;
            map[r + 1][c].c = map[r][c].c;
          }
    }
    
    document.onkeydown = function(event) {
      var keyCode = window .event?event.keyCode:event.which;
    
      if(keyCode == KEY_LEFT ||  keyCode == KEY_RIGHT) {
        easeBlock();
        if(enableShadow)
          easeShadow();
        if(keyCode == KEY_LEFT) {
          if(canLeft())
            --currC;
        } else if(keyCode == KEY_RIGHT) {
          if(canRight())
            ++currC;
        }
        drawBlock();
        if(enableShadow) {
          makeShadow();
          drawShadow();
        }
      } else if(keyCode == KEY_ROTATE) {
        if(canRotate()) {
          easeBlock();
          if(enableShadow)
            easeShadow();
          currDir = [1,2,3,0][currDir];
          drawBlock();
          if(enableShadow) {
            makeShadow();
            drawShadow();
          }
        }
      } else if(keyCode == KEY_ACCELERATE) {
        loop();
      } else if(keyCode == KEY_PAUSE) {
        pause = !pause;
        if(pause)
          clearInterval(timer);
        else
          timer = setInterval(loop, 300);  
      } else if(keyCode == KEY_ONE_STOP) {
        easeBlock();
        makeShadow();
        currR = shadow.r;
        currC = shadow.c;
        drawBlock();  
      }
        
      //printMapState();
    }
    
    function nextBlock() {
      function randInt(n, m) {
        return Math.floor(Math.random() * (m - n)) + n;
      }
    
      currR = 0;
      currC = MAP_C / 2 - BLOCK_C / 2;
      currType = randInt(0, BLOCKS.length);
      currDir = randInt(0, 4);
    }
    
    function printMapState() {
      var debug = $('debug');
      var html = '';
      for(var r = 0; r < MAP_R; r++) {
        for(var c = 0; c < MAP_C; c++)
          html += map[r][c].b;
        html += '</br>';
      }
      debug.innerHTML = html;
    }
    
    onload = function() {
    init();
    nextBlock();
    drawBlock();
    makeShadow();
    drawShadow();
    
    timer = setInterval(loop, 300);
    };
    
    function loop() {
      if(canFall(currR, currC)) {
        easeBlock();
        ++currR;
        drawBlock();
      } else {
        fall();
        if(currR == 0) {
          drawBlock();
          clearInterval(timer);
          alert('Game Over');
          return;
        }
        var rows = checkFullRows();
        if(rows.length > 0) {
          showPop(rows);
          popRows(rows);
          setTimeout(function(){
            drawMap();
          }, 100);
        }
        if(enableShadow)
          easeShadow();
        nextBlock();
        drawBlock();
        if(enableShadow) {
          makeShadow();
          drawShadow();
        }
      }
    }
    
    function drawMap() {
      for(var r = 0; r < MAP_R; r++)
        for(var c = 0; c < MAP_C; c++) {
          var div = $(r + '-' + c);
          if(map[r][c].b) {
            div.style.backgroundColor = colors[map[r][c].c];
          } else {
            div.style.backgroundColor = 'transparent';
          }
        }
    }
    
    function drawBlock() {
      for(var r = 0; r < BLOCK_R; r++)
        for(var c = 0; c < BLOCK_C; c++) {
          if(BLOCKS[currType][currDir][r][c]) {
            var div = $((currR + r) + '-' + (currC + c));
            div.style.backgroundColor = colors[currType];
            div.style.border = '1px solid ' + colors[currType];
          }
        }
    }
    
    function easeBlock() {
      for(var r = 0; r < BLOCK_R; r++)
        for(var c = 0; c < BLOCK_C; c++) {
          if(BLOCKS[currType][currDir][r][c]) {
            var div = $((currR + r) + '-' + (currC + c));
            div.style.backgroundColor = 'transparent';
            div.style.border = '1px solid ' + 'transparent';
          }
        }
    }
    
    function drawShadow() {
      for(var r = 0; r < BLOCK_R; r++)
        for(var c = 0; c < BLOCK_C; c++) {
          if(BLOCKS[currType][currDir][r][c]) {
            var div = $((shadow.r + r) + '-' + (shadow.c + c));
            div.style.border = '1px solid blue';
          }
        }
    }
    
    function easeShadow() {
      for(var r = 0; r < BLOCK_R; r++)
        for(var c = 0; c < BLOCK_C; c++) {
          if(BLOCKS[currType][currDir][r][c]) {
            var div = $((shadow.r + r) + '-' + (shadow.c + c));
            div.style.border = '1px solid ' + 'transparent';
          }
        }
    }
    
    function init() {
      var size = 28;
    
      var space = $('space');
      space.style.position = 'relative';
      space.style.width = size * MAP_C + (MAP_C + 1) * 3 + 1 + 'px';
      space.style.height = size * MAP_R + (MAP_R + 1) * 3 + 1 + 'px';
      //space.style.backgroundColor = 'lavender';
      space.style.border = '2px solid black';
    
      for(var r = 0; r < MAP_R; r++) {
        for(var c = 0; c < MAP_C; c++) {
          var div = document.createElement('div');
          div.id = r + '-' + c;
          div.style.position = 'absolute';
          div.style.top = size * r + (r + 1) * 3 + 'px';
          div.style.left = size * c + (c + 1) * 3 + 'px';
          div.style.width = size + 'px';
          div.style.height = size + 'px';
          space.appendChild(div);
        }
      }
    }
    
    function $(id) {
      return document.getElementById(id);
    }
    </script>
    </html>

     出处:qq群--编程算法&思想 459909287

  • 相关阅读:
    克如斯卡尔 P1546
    真正的spfa
    第四课 最小生成树 要点
    关于vscode中nullptr未定义
    cmake学习笔记
    python学习笔记
    (BFS 图的遍历) 2906. kotori和迷宫
    (图论基础题) leetcode 997. Find the Town Judge
    (BFS DFS 并查集) leetcode 547. Friend Circles
    (BFS DFS 图的遍历) leetcode 841. Keys and Rooms
  • 原文地址:https://www.cnblogs.com/mq0036/p/4946051.html
Copyright © 2011-2022 走看看