JSFiddle - React, Tailwind, and code Playground

by tranxuanthang

HTML

<!doctype html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Tetris Game</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
  </head>
  <body>
    <canvas id="tetris-canvas" width="420" height="600"></canvas>
    <script src="./main.js"></script>
  </body>
</html>

JavaScript

class Game {
  constructor() {
    this.score = 0
    this.boardWidth = 10
    this.boardHeight = 23
    this.currentBoard = new Array(this.boardHeight).fill(0).map(() => new Array(this.boardWidth).fill(0))
    this.landedBoard = new Array(this.boardHeight).fill(0).map(() => new Array(this.boardWidth).fill(0))
    this.currentTetromino = null /* TODO */
    this.canvas = document.getElementById('tetris-canvas')
    this.ctx = this.canvas.getContext('2d')
  }

  draw(blockSize = 24, padding = 4) {
    /* Vẽ khung của board */
    this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
    this.ctx.lineWidth = 2
    this.ctx.rect(padding, padding, blockSize * this.boardWidth + padding * (this.boardWidth + 1), blockSize * (this.boardHeight - 3) + padding * (this.boardHeight - 3 + 1))
    this.ctx.stroke()

    /* Lặp qua các phần tử của mảng board và vẽ các block tại đúng vị trí */
    for (let i = 3; i < this.boardHeight; i++) {
      for (let j = 0; j < this.boardWidth; j++) {
        if (this.currentBoard[i][j] > 0) {
          this.ctx.fillStyle = 'rgb(0, 0, 0)'
        } else {
          this.ctx.fillStyle = 'rgb(248, 248, 248)'
        }
        this.ctx.fillRect(padding * 2 + j * (blockSize + padding), padding * 2 + (i - 3) * (blockSize + padding), blockSize, blockSize)
      }
    }

    /* Viết ra các đoạn text */
    this.ctx.fillStyle = 'rgb(0, 0, 0)'
    this.ctx.font = '28px';
    this.ctx.fillText('TIẾP THEO:', 300, 28)
    this.ctx.fillText('ĐIỂM SỐ:', 300, 200)
    this.ctx.fillText(this.score.toString(), 300, 230)
  }
}

class Tetromino {
  constructor(row, col, angle = 0) {
    if (this.constructor === Tetromino) {
      throw new Error("This is an abstract class.")
    }
    this.row = row
    this.col = col
    this.angle = angle
  }

  get shape() {
    return this.constructor.shapes[this.angle]
  }

  get width() {
    return this.shape[0].length
  }

  get height() {
    return this.shape.length
  }

  fall() {
    this.row += 1
  }

...