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

  • 相关阅读:
    随机抽样一致性算法(RANSAC)
    RANSAC算法详解
    添加“返回顶部”小图标按钮的JS(JavaScript)代码详解
    vue-cli3组件嵌套
    vue-cli3文件的引入
    vue-cli3组件的使用
    vue ui 使用图形化界面
    vue-cli3及以上版本安装及创建项目
    NetTerm共享文件
    Gin框架配置静态文件static
  • 原文地址:https://www.cnblogs.com/mq0036/p/4946051.html
Copyright © 2011-2022 走看看