<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Tetris Game</title> <style> body { display: flex; justify-content: center; align-items: center; height: 100vh; margin: 0; background: #000; } canvas { border: 1px solid #fff; } </style> </head> <body> <canvas id="tetris"></canvas> <script> const canvas = document.getElementById('tetris'); const context = canvas.getContext('2d'); const scale = 20; const columns = 10; const rows = 20; canvas.width = columns * scale; canvas.height = rows * scale; context.scale(scale, scale); function createMatrix(width, height) { const matrix = []; while (height--) { matrix.push(new Array(width).fill(0)); } return matrix; } const tetrominoes = { T: [ [0, 1, 0], [1, 1, 1], [0, 0, 0], ], O: [ [1, 1], [1, 1], ], L: [ [0, 0, 1], [1, 1, 1], [0, 0, 0], ], J: [ [1, 0, 0], [1, 1, 1], [0, 0, 0], ], I: [ [0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0], [0, 0, 0, 0], ], S: [ [0, 1, 1], [1, 1, 0], [0, 0, 0], ], Z: [ [1, 1, 0], [0, 1, 1], [0, 0, 0], ] }; function drawMatrix(matrix, offset) { matrix.forEach((row, y) => { row.forEach((value, x) => { if (value !== 0) { context.fillStyle = 'red'; context.fillRect(x + offset.x, y + offset.y, 1, 1); } }); }); } function merge(arena, player) { player.matrix.forEach((row, y) => { row.forEach((value, x) => { if (value !== 0) { arena[y + player.pos.y][x + player.pos.x] = value; } }); }); } function arenaSweep() { let rowCount = 1; for (let y = arena.length - 1; y > 0; --y) { if (arena[y].every(value => value !== 0)) { arena.splice(y, 1); arena.unshift(new Array(columns).fill(0)); rowCount *= 2; } } } function collide(arena, player) { const [matrix, offset] = [player.matrix, player.pos]; for (let y = 0; y < matrix.length; ++y) { for (let x = 0; x < matrix[y].length; ++x) { if (matrix[y][x] !== 0 && (arena[y + offset.y] && arena[y + offset.y][x + offset.x]) !== 0) { return true; } } } return false; } function playerDrop() { player.pos.y++; if (collide(arena, player)) { player.pos.y--; merge(arena, player); playerReset(); arenaSweep(); } dropCounter = 0; } function playerMove(dir) { player.pos.x += dir; if (collide(arena, player)) { player.pos.x -= dir; } } function rotate(matrix, dir) { for (let y = 0; y < matrix.length; ++y) { for (let x = 0; x < y; ++x) { [matrix[x][y], matrix[y][x]] = [matrix[y][x], matrix[x][y]]; } } if (dir > 0) { matrix.forEach(row => row.reverse()); } else { matrix.reverse(); } } function playerReset() { const pieces = 'TJLOSZI'; player.matrix = tetrominoes[pieces[pieces.length * Math.random() | 0]]; player.pos.y = 0; player.pos.x = (columns / 2 | 0) - (player.matrix[0].length / 2 | 0); if (collide(arena, player)) { arena.forEach(row => row.fill(0)); } } let dropCounter = 0; let dropInterval = 1000; let lastTime = 0; function update(time = 0) { const deltaTime = time - lastTime; lastTime = time; dropCounter += deltaTime; if (dropCounter > dropInterval) { playerDrop(); } draw(); requestAnimationFrame(update); } function draw() { context.fillStyle = '#000'; context.fillRect(0, 0, canvas.width / scale, canvas.height / scale); drawMatrix(arena, { x: 0, y: 0 }); drawMatrix(player.matrix, player.pos); } const player = { pos: { x: 0, y: 0 }, matrix: null, }; const arena = createMatrix(columns, rows); playerReset(); update(); document.addEventListener('keydown', event => { if (event.key === 'ArrowLeft') { playerMove(-1); } else if (event.key === 'ArrowRight') { playerMove(1); } else if (event.key === 'ArrowDown') { playerDrop(); } else if (event.key === 'ArrowUp') { rotate(player.matrix, 1); } }); </script> </body> </html>