UNPKG

one-yeheng

Version:

A simple Tetris game

186 lines (170 loc) 5.25 kB
const canvas = document.getElementById('tetris'); const context = canvas.getContext('2d'); const startButton = document.getElementById('start-button'); const ROWS = 20; // 行数 const COLS = 10; // 列数 const BLOCK_SIZE = 30; // 每个方块的大小 const shapes = [ [[1, 1, 1, 1]], // I [[1, 1], [1, 1]], // O [[0, 1, 0], [1, 1, 1]], // T [[1, 1, 0], [0, 1, 1]], // Z [[0, 1, 1], [1, 1, 0]], // S [[1, 0, 0], [1, 1, 1]], // L [[0, 0, 1], [1, 1, 1]] // J ]; let board = Array.from({ length: ROWS }, () => Array(COLS).fill(0)); let currentPiece = createPiece(); let score = 0; let gameActive = false; // 游戏是否正在进行 // 创建随机方块 function createPiece() { const type = shapes[Math.floor(Math.random() * shapes.length)]; return { shape: type, x: Math.floor(COLS / 2) - Math.floor(type[0].length / 2), y: 0 }; } // 绘制方块 function drawPiece(piece) { piece.shape.forEach((row, y) => { row.forEach((value, x) => { if (value) { context.fillStyle = 'cyan'; context.fillRect((piece.x + x) * BLOCK_SIZE, (piece.y + y) * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE); context.strokeStyle = 'black'; context.strokeRect((piece.x + x) * BLOCK_SIZE, (piece.y + y) * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE); } }); }); } // 绘制游戏板 function drawBoard() { board.forEach((row, y) => { row.forEach((value, x) => { if (value) { context.fillStyle = 'blue'; context.fillRect(x * BLOCK_SIZE, y * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE); context.strokeStyle = 'black'; context.strokeRect(x * BLOCK_SIZE, y * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE); } }); }); } // 碰撞检测 function collide(board, piece) { for (let y = 0; y < piece.shape.length; y++) { for (let x = 0; x < piece.shape[y].length; x++) { if ( piece.shape[y][x] && (board[piece.y + y] && board[piece.y + y][piece.x + x]) !== 0 ) { return true; } } } return false; } // 固定方块 function freeze() { currentPiece.shape.forEach((row, y) => { row.forEach((value, x) => { if (value) { board[currentPiece.y + y][currentPiece.x + x] = value; } }); }); } // 消除行 function clearLines() { let linesCleared = 0; board.forEach((row, y) => { if (row.every(cell => cell !== 0)) { board.splice(y, 1); board.unshift(Array(COLS).fill(0)); linesCleared++; } }); if (linesCleared > 0) { score += linesCleared * 10; document.getElementById('score').innerText = `得分: ${score}`; } } // 更新游戏状态 function update() { if (!gameActive) return; // 如果游戏未开始,则不更新游戏状态 currentPiece.y++; // 方块下落 if (collide(board, currentPiece)) { currentPiece.y--; // 如果碰撞,回退一步 freeze(); // 固定方块 clearLines(); // 消除满行 currentPiece = createPiece(); // 生成新方块 if (collide(board, currentPiece)) { // 如果新方块也碰撞,游戏结束 alert(`游戏结束!得分: ${score}`); gameActive = false; // 标记游戏为未进行中 startButton.textContent = '重新开始'; // 修改按钮文字 } } } // 渲染游戏 function render() { context.clearRect(0, 0, canvas.width, canvas.height); drawBoard(); drawPiece(currentPiece); } // 游戏循环 function gameLoop() { update(); render(); setTimeout(gameLoop, 500); } // 键盘控制 document.addEventListener('keydown', event => { if (!gameActive) return; // 如果游戏未开始,则不响应键盘事件 if (event.key === 'ArrowLeft') { currentPiece.x--; if (collide(board, currentPiece)) { currentPiece.x++; } } else if (event.key === 'ArrowRight') { currentPiece.x++; if (collide(board, currentPiece)) { currentPiece.x--; } } else if (event.key === 'ArrowDown') { currentPiece.y++; if (collide(board, currentPiece)) { currentPiece.y--; } } else if (event.key === 'ArrowUp') { const rotated = rotate(currentPiece.shape); if (!collide(board, { ...currentPiece, shape: rotated })) { currentPiece.shape = rotated; } } }); // 旋转方块 function rotate(piece) { const N = piece.length; const rotated = Array.from({ length: N }, () => Array(N).fill(0)); for (let y = 0; y < N; y++) { for (let x = 0; x < N; x++) { rotated[x][N - 1 - y] = piece[y][x]; } } return rotated; } // 启动游戏 function startGame() { if (gameActive) return; // 如果游戏已经在进行中,则不再重复启动 gameActive = true; // 标记游戏为进行中 board = Array.from({ length: ROWS }, () => Array(COLS).fill(0)); // 初始化游戏板 currentPiece = createPiece(); // 生成初始方块 score = 0; // 重置得分 document.getElementById('score').innerText = `得分: ${score}`; // 更新得分显示 gameLoop(); // 启动游戏循环 } // 绑定按钮点击事件 startButton.addEventListener('click', startGame);