テトリス

操作方法

  • ← → : 左右移動
  • ↓ : 加速落下
  • ↑ : 回転
  • ライン消すとスコア+100/ライン
  • 積み上がってゲームオーバーになったらアラート出る
Simple Tetris – Elon Style
Score: 0
GAME OVER

<テトリス>使用コード

テトリスを作るにあたり使用したコードです。
ご自由にコピペしてお使いください。
私は人間ですので誤りがあるかもしれません。その際にはご自分でご調整ください。

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>Simple Tetris - Elon Style</title>
  <style>
    body {
      margin: 0;
      height: 100vh;
      background: #000;
      display: flex;
      justify-content: center;
      align-items: center;
      font-family: Arial, sans-serif;
    }
    #game {
      position: relative;
    }
    canvas {
      border: 4px solid #333;
      background: #111;
      box-shadow: 0 0 30px rgba(0, 255, 255, 0.3);
    }
    #info {
      position: absolute;
      top: 10px;
      left: 10px;
      color: #0ff;
      font-size: 18px;
      text-shadow: 0 0 10px #0ff;
    }
    #next {
      position: absolute;
      top: 60px;
      right: -140px;
      width: 120px;
      height: 120px;
      background: #222;
      border: 2px solid #444;
    }
    #game-over {
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
      color: #f00;
      font-size: 48px;
      font-weight: bold;
      text-shadow: 0 0 20px #f00;
      display: none;
    }
  </style>
</head>
<body>
  <div id="game">
    <canvas id="tetris" width="240" height="480"></canvas>
    <div id="info">Score: <span id="score">0</span></div>
    <canvas id="next" width="120" height="120"></canvas>
    <div id="game-over">GAME OVER</div>
  </div>

  <script>
    const BOARD_WIDTH = 10;
    const BOARD_HEIGHT = 20;
    const BLOCK_SIZE = 24;

    const canvas = document.getElementById('tetris');
    const ctx = canvas.getContext('2d');
    const nextCanvas = document.getElementById('next');
    const nextCtx = nextCanvas.getContext('2d');

    const scoreElement = document.getElementById('score');
    const gameOverElement = document.getElementById('game-over');

    const PIECES = [
      [[1,1,1,1]],           // I
      [[1,1],[1,1]],         // O
      [[0,1,0],[1,1,1]],     // T
      [[0,1,1],[1,1,0]],     // S
      [[1,1,0],[0,1,1]],     // Z
      [[1,0,0],[1,1,1]],     // J
      [[0,0,1],[1,1,1]]      // L
    ];

    const COLORS = ['#00f0f0','#ffff00','#a000f0','#00f000','#f00000','#0000f0','#f0a000'];

    let board = Array(BOARD_HEIGHT).fill().map(() => Array(BOARD_WIDTH).fill(0));
    let score = 0;
    let dropCounter = 0;
    let dropInterval = 1000;
    let lastTime = 0;
    let gameRunning = true;

    let piece = createPiece();
    let nextPiece = createPiece();

    function createPiece() {
      const type = Math.floor(Math.random() * PIECES.length);
      return {
        shape: PIECES[type],
        color: type,
        x: Math.floor(BOARD_WIDTH / 2) - Math.floor(PIECES[type][0].length / 2),
        y: 0
      };
    }

    function drawBlock(ctx, x, y, color) {
      ctx.fillStyle = COLORS[color];
      ctx.fillRect(x * BLOCK_SIZE, y * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE);
      ctx.strokeStyle = '#000';
      ctx.strokeRect(x * BLOCK_SIZE, y * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE);
    }

    function draw() {
      ctx.clearRect(0, 0, canvas.width, canvas.height);
      nextCtx.clearRect(0, 0, nextCanvas.width, nextCanvas.height);

      // 固定されたブロック描画
      board.forEach((row, y) => {
        row.forEach((value, x) => {
          if (value) drawBlock(ctx, x, y, value - 1);
        });
      });

      // 現在のピース描画
      piece.shape.forEach((row, y) => {
        row.forEach((value, x) => {
          if (value) drawBlock(ctx, piece.x + x, piece.y + y, piece.color);
        });
      });

      // NEXT描画
      nextPiece.shape.forEach((row, y) => {
        row.forEach((value, x) => {
          if (value) drawBlock(nextCtx, x + 1, y + 1, nextPiece.color);
        });
      });
    }

    function collide() {
      return piece.shape.some((row, y) => 
        row.some((value, x) => 
          value && (board[piece.y + y] && board[piece.y + y][piece.x + x]) !== 0
        )
      );
    }

    function merge() {
      piece.shape.forEach((row, y) => {
        row.forEach((value, x) => {
          if (value) {
            board[piece.y + y][piece.x + x] = piece.color + 1;
          }
        });
      });
    }

    function clearLines() {
      let lines = 0;
      outer: for (let y = BOARD_HEIGHT - 1; y >= 0; y--) {
        for (let x = 0; x < BOARD_WIDTH; x++) {
          if (!board[y][x]) continue outer;
        }
        board.splice(y, 1);
        board.unshift(Array(BOARD_WIDTH).fill(0));
        lines++;
        y++;
      }
      if (lines > 0) {
        score += [0, 100, 300, 500, 800][lines];
        scoreElement.textContent = score;
      }
    }

    function drop() {
      piece.y++;
      if (collide()) {
        piece.y--;
        merge();
        clearLines();
        piece = nextPiece;
        nextPiece = createPiece();
        if (collide()) {
          gameRunning = false;
          gameOverElement.style.display = 'block';
        }
      }
      dropCounter = 0;
    }

    function move(dir) {
      piece.x += dir;
      if (collide()) piece.x -= dir;
    }

    function rotate() {
      const original = piece.shape;
      piece.shape = piece.shape[0].map((_, i) => 
        piece.shape.map(row => row[i]).reverse()
      );
      if (collide()) piece.shape = original;
    }

    document.addEventListener('keydown', e => {
      if (!gameRunning) return;
      if (e.key === 'ArrowLeft') move(-1);
      if (e.key === 'ArrowRight') move(1);
      if (e.key === 'ArrowDown') drop();
      if (e.key === 'ArrowUp') rotate();
      if (e.key === ' ') { // ハードドロップ
        while (!collide()) piece.y++;
        piece.y--;
        drop();
      }
    });

    function update(time = 0) {
      if (!gameRunning) return;
      const delta = time - lastTime;
      lastTime = time;

      dropCounter += delta;
      if (dropCounter > dropInterval) drop();

      draw();
      requestAnimationFrame(update);
    }

    draw();
    update();
  </script>
</body>
</html>