点击查看html编辑器说明文档

俄罗斯方块小游戏edit icon

|
|
Fork(复制)
|
|
作者:
用户fkxIv10
提交反馈
嵌入
设置
下载
HTML
格式化
支持Emmet,输入 p 后按 Tab键试试吧!
<head> ...
展开
</head>
<body>
<div id="tetris"></div>
</body>
CSS
格式化
body {
  background-color: #cfd8dc;
}

#tetris {
  display: inline-block;
}

#tetris div.ui {
  display: inline-block;
  margin: 5px;
  margin-top: 10px;
  vertical-align: top;
}

#tetris div.game {
  display: inline-block;
}

#tetris table {
  margin: 10px;
  border-collapse: collapse;
  -webkit-box-shadow: -5px 5px 15px #607d8b;
  box-shadow: -5px 5px 15px #607d8b;
}

#tetris .glass tr:first-child {
  display: none;
}

#tetris td {
  width: 20px;
  height: 20px;
  background-color: #f5f5f5;
}

#tetris td.j {
  background-color: #3f51b5;
}

#tetris td.l {
  background-color: #4caf50;
}

#tetris td.o {
  background-color: #e91e63;
}

#tetris td.i {
  background-color: #009688;
}

#tetris td.s {
  background-color: #9c27b0;
}

#tetris td.t {
  background-color: #ffc107;
}

#tetris td.z {
  background-color: #00bcd4;
}

#tetris .score-field {
  font: 1.5em sans-serif;
  display: inline-block;
  margin: 15px;
  padding: 5px;
  border: 1px solid #607d8b;
  background-color: #f5f5f5;
  -webkit-box-shadow: -5px 5px 15px #607d8b;
  box-shadow: -5px 5px 15px #607d8b;
}
JS
格式化
/**
 * @param options Parameters
 * @param options.elem DOM element for component
 * @param options.width Width of game field
 * @param options.height Height of game field
 */
function Tetris(options) {
  var elem = options.elem;
  var width = (+options.width < 10) ? 10 : ~~(+options.width);
  var height = (+options.height < 20) ? 21 : ~~(+options.height + 1);

  var controlTimeoutHandle;
  var fallingTimeoutHandle;

  var predictionField;
  var scoreField;
  var gameField;

  var tetraminoForms = [
    [
      ['i', 'i', 'i', 'i']
    ],

    [
      ['j', '.', '.'],
      ['j', 'j', 'j']
    ],

    [
      ['.', '.', 'l'],
      ['l', 'l', 'l']
    ],

    [
      ['o', 'o'],
      ['o', 'o']
    ],

    [
      ['.', 's', 's'],
      ['s', 's', '.']
    ],

    [
      ['.', 't', '.'],
      ['t', 't', 't']
    ],

    [
      ['z', 'z', '.'],
      ['.', 'z', 'z']
    ]
  ];

  var fieldArray = [];

  var currentTetramino;
  var nextTetramino;

  var coordsToMove = [0, 0];

  var fallSpeed = 1000;

  function generateComponent() {

    function generateUI() {
      var divUi = document.createElement('div');

      predictionField = document.createElement('table');

      for (var i = 0; i < 4; i++) {
        var tr = document.createElement('tr');
        for (var j = 0; j < 4; j++) {
          var td = document.createElement('td');
          tr.appendChild(td);
        }
        predictionField.appendChild(tr);
      }

      scoreField = document.createElement('div');
      scoreField.classList.add('score-field');
      scoreField.innerHTML = 0;

      divUi.appendChild(predictionField);
      divUi.appendChild(scoreField);

      divUi.classList.add('ui');

      elem.appendChild(divUi);
    }

    function generateGlassUI() {
      var divGameField = document.createElement('div');

      gameField = document.createElement('table');
      gameField.classList.add('glass')

      for (var i = 0; i < height; i++) {
        var tr = document.createElement('tr');
        for (var j = 0; j < width; j++) {
          var td = document.createElement('td');
          tr.appendChild(td);
        }
        gameField.appendChild(tr);
      }

      divGameField.appendChild(gameField);

      divGameField.classList.add('game');

      elem.appendChild(divGameField);
    }

    function generateFieldArray() {
      for (var i = 0; i < height; i++) {
        fieldArray.push([]);
        for (var j = 0; j < width; j++) {
          fieldArray[i].push('.');
        }
      }
    }

    generateUI();
    generateGlassUI();
    generateFieldArray();
  }

  // ------------- Tetramino Class ------------------

  function Tetramino(type) {
    this.form = tetraminoForms[type].slice(0);
    this.coords = [~~(width / 2) - ~~(tetraminoForms[type][0].length / 2), 0];
    this.prevCoords;
  }

  Tetramino.prototype.rotate = function() {
    var temp = new Array(this.form[0].length);

    for (var i = 0; i < temp.length; i++) {
      temp[i] = new Array(this.form.length);
      for (var j = 0; j < temp[i].length; j++) {
        temp[i][j] = this.form[temp[i].length - j - 1][i];
      }
    }

    for (var i = 0; i < temp.length; i++) {
      for (var j = 0; j < temp[i].length; j++) {
        if (fieldArray[this.coords[1] + i] !== undefined &&
          fieldArray[this.coords[1] + i][this.coords[0] + j] !== undefined &&
          fieldArray[this.coords[1] + i][this.coords[0] + j] === '.') {

          continue;
        } else {
          return;
        }
      }
    }

    this.form = temp;
  };

  Tetramino.prototype.control = function(coords) {
    if (coords[0] === 0 && coords[1] === -1) {
      this.rotate();
      return;
    }

    if (this.coords[0] + coords[0] >= 0 &&
      this.coords[0] + coords[0] + this.form[0].length <= fieldArray[0].length) {

      if (checkSideCoords(this.coords[0] + coords[0], coords[0])) {
        this.coords[0] += coords[0];
      }
    }

    if (this.coords[1] + coords[1] >= 0 &&
      this.coords[1] + coords[1] + this.form.length <= fieldArray.length) {
      this.coords[1] += coords[1];
    }
  };

  // ----------- Tetramino Class End ---------------

  function drawField() {
    for (var i = 0; i < fieldArray.length; i++) {
      for (var j = 0; j < fieldArray[i].length; j++) {
        gameField.rows[i].cells[j].className = '';
        gameField.rows[i].cells[j].classList.add(fieldArray[i][j]);
      }
    }
  }

  function drawNextTetramino() {
    for (var i = 0; i < 4; i++) {
      for (var j = 0; j < 4; j++) {
        predictionField.rows[i].cells[j].className = '';
      }
    }

    for (var i = 0; i < nextTetramino.form.length; i++) {
      for (var j = 0; j < nextTetramino.form[i].length; j++) {
        predictionField.rows[i].cells[j].classList.add(nextTetramino.form[i][j]);
      }
    }
  }

  function controlTetramino(event) {
    var code = event.keyCode;

    if (code === 37) coordsToMove = [-1, 0];
    if (code === 38) coordsToMove = [0, -1];
    if (code === 39) coordsToMove = [1, 0];
    if (code === 40) coordsToMove = [0, 1];
  }

  function runTetris() {
    currentTetramino = new Tetramino(Math.floor(Math.random() * (6 + 1)));
    nextTetramino = new Tetramino(Math.floor(Math.random() * (6 + 1)));

    drawNextTetramino();

    moveTetramino();
    fallTetramino();
  }

  function moveTetramino() {
    controlTimeoutHandle = setTimeout(function() {

      if (currentTetramino.prevCoords) {
        for (var i = 0; i < currentTetramino.form.length; i++) {
          for (var j = 0; j < currentTetramino.form[i].length; j++) {
            if (currentTetramino.form[i][j] == '.') continue;
            fieldArray[i + currentTetramino.prevCoords[1]][j + currentTetramino.prevCoords[0]] = '.';
          }
        }
      }

      currentTetramino.control(coordsToMove);

      for (var i = 0; i < currentTetramino.form.length; i++) {
        for (var j = 0; j < currentTetramino.form[i].length; j++) {
          if (currentTetramino.form[i][j] == '.') continue;
          fieldArray[i + currentTetramino.coords[1]][j + currentTetramino.coords[0]] = currentTetramino.form[i][j];
        }
      }

      currentTetramino.prevCoords = currentTetramino.coords.slice(0);
      coordsToMove = [0, 0];

      drawField();
      checkBlocksUnderTetramino();

      moveTetramino();
    }, 0);
  }

  function fallTetramino() {
    fallingTimeoutHandle = setTimeout(function() {

      coordsToMove = [0, 1];

      fallTetramino();
    }, fallSpeed);
  }

  function checkBlocksUnderTetramino() {
    if (currentTetramino.coords[1] + currentTetramino.form.length === fieldArray.length) {
      changeTetramino();
      return;
    }

    for (var i = currentTetramino.form.length - 1; i >= 0; i--) {
      for (var j = currentTetramino.form[i].length - 1; j >= 0; j--) {

        if (currentTetramino.form[i][j] === '.') continue;

        if (fieldArray[currentTetramino.coords[1] + i + 1][currentTetramino.coords[0] + j] !== '.' &&
          fieldArray[currentTetramino.coords[1] + i][currentTetramino.coords[0] + j] !== '.' &&
          (currentTetramino.form[i + 1] === undefined || currentTetramino.form[i + 1][j] === '.')) {
          changeTetramino();
          return;
        }
      }
    }
  }

  function checkSideCoords(coords, side) {
    if (coords === 0 && coords === fieldArray[0].length) {
      return false;
    }

    var side = (side === -1) ? -1 : currentTetramino.form[0].length;

    for (var i = 0; i < currentTetramino.form.length; i++) {
      if (fieldArray[currentTetramino.coords[1] + i][currentTetramino.coords[0] + side] !== '.' &&
        currentTetramino.form[i][(side === -1) ? 0 : currentTetramino.form[0].length - 1] !== '.') {
        return false;
      }
    }

    return true;
  }

  function changeTetramino() {
    checkAndRemoveFilledRow();

    isGameOver();

    currentTetramino = nextTetramino;
    nextTetramino = new Tetramino(Math.floor(Math.random() * (6 + 1)));
    drawNextTetramino();
    scoreField.innerHTML++;
  }

  function checkAndRemoveFilledRow() {
    for (var i = 0; i < fieldArray.length; i++) {
      var toClean = true;
      for (var j = 0; j < fieldArray[i].length; j++) {
        if (fieldArray[i][j] === '.') {
          toClean = false;
          break;
        }
      }
      if (toClean) {
        fieldArray.splice(i, 1);
        fieldArray.unshift([]);

        for (var j = 0; j < width; j++) {
          fieldArray[0].push('.');
        }

        scoreField.innerHTML = +scoreField.innerHTML + width;
        fallSpeed = (fallSpeed > 300) ? fallSpeed - 50 : fallSpeed;
      }
    }
  }

  function isGameOver() {
    if (currentTetramino.coords[1] <= 1) {
      alert('game over');
      resetGame();
    }
  }

  function resetGame() {
    for (var i = 0; i < fieldArray.length; i++) {
      for (var j = 0; j < fieldArray[i].length; j++) {
        fieldArray[i][j] = '.';
      }
    }

    scoreField.innerHTML = 0;
    fallSpeed = 1000;
  }

  generateComponent();
  drawField();
  document.body.addEventListener('keydown', controlTetramino, false);
  runTetris();
}

var tetris = new Tetris({
  elem: document.getElementById('tetris'),
  width: 10,
  height: 20
});
预览
控制台