JS实现——俄罗斯方块

Posted 7qin

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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>

https://www.cnblogs.com/mq0036/p/4946051.html

以上是关于JS实现——俄罗斯方块的主要内容,如果未能解决你的问题,请参考以下文章

js实现一款俄罗斯方块

C# 俄罗斯方块源代码

js 实现俄罗斯方块

[从零开始]使用Vue.js制作俄罗斯方块小游戏ui实现

《JavaScript100例|01》之javaScript实现俄罗斯方块,唤起了女朋友儿时的回忆!

纯JavaScript实现俄罗斯方块(详细注释