俄罗斯方块

52 阅读1分钟

index.html

Tetris canvas { border: 2px solid #333; } body { display: flex; gap: 20px; padding: 20px; }

Score: 0

New Game

tetris.js

const canvas = document.getElementById('game'); const ctx = canvas.getContext('2d'); const BLOCK_SIZE = 30; const COLS = 10; const ROWS = 20;

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

let board = Array(ROWS).fill().map(() => Array(COLS).fill(0)); let currentPiece = null; let score = 0;

function createPiece() { const index = Math.floor(Math.random() * SHAPES.length); return { shape: SHAPES[index], x: Math.floor(COLS/2) - 1, y: 0 }; }

function drawBlock(x, y) { ctx.fillRect(x * BLOCK_SIZE, y * BLOCK_SIZE, BLOCK_SIZE-1, BLOCK_SIZE-1); }

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

// Draw board for(let y = 0; y < ROWS; y++) { for(let x = 0; x < COLS; x++) { if(board[y][x]) { ctx.fillStyle = '#333'; drawBlock(x, y); } } }

// Draw current piece if(currentPiece) { ctx.fillStyle = '#f00'; currentPiece.shape.forEach((row, dy) => { row.forEach((value, dx) => { if(value) { drawBlock(currentPiece.x + dx, currentPiece.y + dy); } }); }); } }

function collision() { return currentPiece.shape.some((row, dy) => { return row.some((value, dx) => { if(!value) return false; const nx = currentPiece.x + dx; const ny = currentPiece.y + dy; return nx < 0 || nx >= COLS || ny >= ROWS || board[ny][nx]; }); }); }

function merge() { currentPiece.shape.forEach((row, dy) => { row.forEach((value, dx) => { if(value) { const ny = currentPiece.y + dy; const nx = currentPiece.x + dx; if(ny >= 0) board[ny][nx] = 1; } }); }); }

function clearLines() { let linesCleared = 0; for(let y = ROWS-1; y >= 0; y--) { if(board[y].every(cell => cell)) { board.splice(y, 1); board.unshift(Array(COLS).fill(0)); linesCleared++; y++; } } if(linesCleared) { score += linesCleared * 100; document.getElementById('score').textContent = score; } }

function rotate() { const newShape = currentPiece.shape[0].map((_, i) => currentPiece.shape.map(row => row[i]).reverse() ); const oldShape = currentPiece.shape; currentPiece.shape = newShape; if(collision()) { currentPiece.shape = oldShape; } }

function move(dir) { currentPiece.x += dir; if(collision()) currentPiece.x -= dir; }

function drop() { currentPiece.y++; if(collision()) { currentPiece.y--; merge(); clearLines(); currentPiece = createPiece(); if(collision()) { alert('Game Over!'); resetGame(); } } }

function resetGame() { board = Array(ROWS).fill().map(() => Array(COLS).fill(0)); score = 0; document.getElementById('score').textContent = score; currentPiece = createPiece(); }

function startGame() { resetGame(); function update() { drop(); draw(); requestAnimationFrame(update); } update(); }

// Controls document.addEventListener('keydown', e => { if(!currentPiece) return; switch(e.keyCode) { case 37: move(-1); break; // left case 39: move(1); break; // right case 40: drop(); break; // down case 38: rotate(); break; // up } draw(); });