DeepSeek俄罗斯方块源码

发布于 2025年5月29日

本文内容由AI生成并经过人工精选,不保证100%准确,请酌情参考使用

DeepSeekR1

俄罗斯方块游戏实现

下面是一个使用HTML Canvas实现的完整俄罗斯方块游戏:

<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>俄罗斯方块</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; } body { display: flex; justify-content: center; align-items: center; min-height: 100vh; background: linear-gradient(135deg, #1a2a6c, #b21f1f, #1a2a6c); font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; color: white; padding: 20px; } .game-container { display: flex; gap: 30px; max-width: 900px; background: rgba(0, 0, 0, 0.7); border-radius: 15px; padding: 25px; box-shadow: 0 15px 30px rgba(0, 0, 0, 0.5); backdrop-filter: blur(10px); } .game-header { text-align: center; margin-bottom: 25px; } .game-header h1 { font-size: 2.8rem; text-shadow: 0 0 10px #00b3ff, 0 0 20px #00b3ff; letter-spacing: 3px; margin-bottom: 10px; } .game-header p { font-size: 1.1rem; opacity: 0.8; } .game-board { position: relative; } canvas { display: block; background: rgba(10, 15, 35, 0.9); border-radius: 8px; box-shadow: 0 0 15px rgba(0, 150, 255, 0.5); } #game-canvas { border: 2px solid #00b3ff; } #next-piece { border: 2px solid #ff00aa; } .side-panel { display: flex; flex-direction: column; gap: 25px; min-width: 200px; } .panel-section { background: rgba(30, 40, 80, 0.8); border-radius: 10px; padding: 20px; box-shadow: 0 5px 15px rgba(0, 0, 0, 0.4); } .panel-title { font-size: 1.3rem; margin-bottom: 15px; color: #00e5ff; text-align: center; border-bottom: 2px solid #00e5ff; padding-bottom: 8px; } .stats { display: grid; grid-template-columns: 1fr 1fr; gap: 15px; } .stat-item { text-align: center; } .stat-label { font-size: 1rem; opacity: 0.8; margin-bottom: 5px; } .stat-value { font-size: 1.8rem; font-weight: bold; color: #ffcc00; } .controls { display: grid; grid-template-columns: repeat(2, 1fr); gap: 10px; } .control-item { display: flex; flex-direction: column; align-items: center; } .key { background: rgba(0, 0, 0, 0.5); border: 1px solid #00b3ff; border-radius: 5px; padding: 8px 15px; font-size: 1.2rem; margin-bottom: 5px; min-width: 60px; text-align: center; } .control-label { font-size: 0.9rem; opacity: 0.8; text-align: center; } .next-piece-container { display: flex; flex-direction: column; align-items: center; } #next-piece { background: rgba(10, 15, 35, 0.9); margin-top: 10px; } .buttons { display: flex; flex-direction: column; gap: 15px; } button { background: linear-gradient(to bottom, #ff00aa, #b30077); color: white; border: none; border-radius: 50px; padding: 12px 25px; font-size: 1.1rem; font-weight: bold; cursor: pointer; transition: all 0.3s ease; box-shadow: 0 5px 15px rgba(179, 0, 119, 0.4); } button:hover { background: linear-gradient(to bottom, #ff33bb, #cc0088); transform: translateY(-3px); box-shadow: 0 8px 20px rgba(179, 0, 119, 0.6); } button:active { transform: translateY(1px); } .game-over { position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0, 0, 0, 0.85); display: flex; flex-direction: column; justify-content: center; align-items: center; border-radius: 8px; z-index: 10; display: none; } .game-over h2 { font-size: 3rem; color: #ff3333; margin-bottom: 20px; text-shadow: 0 0 10px #ff0000; } .game-over p { font-size: 1.5rem; margin-bottom: 30px; color: #ffcc00; } .instructions { margin-top: 25px; font-size: 0.9rem; opacity: 0.7; text-align: center; line-height: 1.6; } @media (max-width: 768px) { .game-container { flex-direction: column; align-items: center; } .side-panel { width: 100%; max-width: 400px; } } </style> </head> <body> <div class="game-container"> <div class="game-board"> <div class="game-header"> <h1>俄罗斯方块</h1> <p>经典益智游戏</p> </div> <canvas id="game-canvas" width="300" height="600"></canvas> <div class="game-over" id="game-over"> <h2>游戏结束!</h2> <p>得分: <span id="final-score">0</span></p> <button id="restart-btn">重新开始</button> </div> </div> <div class="side-panel"> <div class="panel-section"> <div class="panel-title">游戏信息</div> <div class="stats"> <div class="stat-item"> <div class="stat-label">分数</div> <div class="stat-value" id="score">0</div> </div> <div class="stat-item"> <div class="stat-label">行数</div> <div class="stat-value" id="lines">0</div> </div> <div class="stat-item"> <div class="stat-label">等级</div> <div class="stat-value" id="level">1</div> </div> <div class="stat-item"> <div class="stat-label">下一个</div> </div> </div> <div class="next-piece-container"> <canvas id="next-piece" width="150" height="150"></canvas> </div> </div> <div class="panel-section"> <div class="panel-title">游戏控制</div> <div class="controls"> <div class="control-item"> <div class="key"></div> <div class="control-label">左移</div> </div> <div class="control-item"> <div class="key"></div> <div class="control-label">右移</div> </div> <div class="control-item"> <div class="key"></div> <div class="control-label">加速</div> </div> <div class="control-item"> <div class="key"></div> <div class="control-label">旋转</div> </div> <div class="control-item"> <div class="key">空格</div> <div class="control-label">直接落下</div> </div> <div class="control-item"> <div class="key">P</div> <div class="control-label">暂停</div> </div> </div> </div> <div class="panel-section buttons"> <button id="start-btn">开始游戏</button> <button id="pause-btn">暂停游戏</button> <button id="reset-btn">重新开始</button> </div> <div class="instructions"> 目标:填满整行以消除方块,获得分数<br> 随着等级提高,方块下落速度会加快 </div> </div> </div> <script> // 游戏常量 const COLS = 10; const ROWS = 20; const BLOCK_SIZE = 30; const COLORS = [ null, '#FF0D72', // I '#0DC2FF', // J '#0DFF72', // L '#F538FF', // O '#FF8E0D', // S '#FFE138', // T '#3877FF' // Z ]; // 方块形状定义 const SHAPES = [ [], [[0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0], [0, 0, 0, 0]], // I [[0, 0, 0], [1, 1, 1], [0, 0, 1]], // J [[0, 0, 0], [1, 1, 1], [1, 0, 0]], // L [[0, 0, 0, 0], [0, 1, 1, 0], [0, 1, 1, 0], [0, 0, 0, 0]], // O [[0, 0, 0], [0, 1, 1], [1, 1, 0]], // S [[0, 0, 0], [0, 1, 0], [1, 1, 1]], // T [[0, 0, 0], [1, 1, 0], [0, 1, 1]] // Z ]; // 游戏变量 let canvas, ctx, nextCanvas, nextCtx; let board = []; let currentPiece, nextPiece; let score = 0, lines = 0, level = 1; let gameOver = false; let isPaused = false; let dropCounter = 0; let dropInterval = 1000; let lastTime = 0; let animationId; // 初始化游戏 function init() { canvas = document.getElementById('game-canvas'); ctx = canvas.getContext('2d'); nextCanvas = document.getElementById('next-piece'); nextCtx = nextCanvas.getContext('2d'); // 计算画布大小 canvas.width = COLS * BLOCK_SIZE; canvas.height = ROWS * BLOCK_SIZE; nextCanvas.width = 150; nextCanvas.height = 150; // 初始化游戏板 createBoard(); // 创建第一个方块 resetGame(); // 添加事件监听器 document.addEventListener('keydown', handleKeyPress); document.getElementById('start-btn').addEventListener('click', startGame); document.getElementById('pause-btn').addEventListener('click', togglePause); document.getElementById('reset-btn').addEventListener('click', resetGame); document.getElementById('restart-btn').addEventListener('click', resetGame); } // 创建游戏板 function createBoard() { board = Array.from({ length: ROWS }, () => Array(COLS).fill(0)); } // 重置游戏 function resetGame() { createBoard(); score = 0; lines = 0; level = 1; gameOver = false; isPaused = false; dropInterval = 1000; // 隐藏游戏结束画面 document.getElementById('game-over').style.display = 'none'; // 创建新方块 createPiece(); // 更新分数显示 updateStats(); // 如果之前有动画,取消 if (animationId) { cancelAnimationFrame(animationId); } } // 开始游戏 function startGame() { if (gameOver) { resetGame(); } isPaused = false; lastTime = 0; animationId = requestAnimationFrame(gameLoop); } // 暂停/继续游戏 function togglePause() { isPaused = !isPaused; if (!isPaused && !gameOver) { lastTime = 0; animationId = requestAnimationFrame(gameLoop); } } // 创建新方块 function createPiece() { // 如果还没有下一个方块,创建一个 if (!nextPiece) { nextPiece = { shape: Math.floor(Math.random() * 7) + 1, x: Math.floor(COLS / 2) - 1, y: 0 }; } // 当前方块设置为下一个方块 currentPiece = { shape: nextPiece.shape, x: Math.floor(COLS / 2) - 1, y: 0 }; // 创建新的下一个方块 nextPiece = { shape: Math.floor(Math.random() * 7) + 1, x: 0, y: 0 }; // 绘制下一个方块预览 drawNextPiece(); // 检查游戏是否结束 if (checkCollision()) { gameOver = true; document.getElementById('game-over').style.display = 'flex'; document.getElementById('final-score').textContent = score; } } // 游戏主循环 function gameLoop(time = 0) { const deltaTime = time - lastTime; lastTime = time; if (!isPaused && !gameOver) { dropCounter += deltaTime; if (dropCounter > dropInterval) { dropPiece(); dropCounter = 0; } draw(); animationId = requestAnimationFrame(gameLoop); } } // 绘制游戏 function draw() { // 清空画布 ctx.clearRect(0, 0, canvas.width, canvas.height); // 绘制已落下的方块 drawBoard(); // 绘制当前方块 drawPiece(currentPiece); } // 绘制游戏板上的方块 function drawBoard() { for (let y = 0; y < ROWS; y++) { for (let x = 0; x < COLS; x++) { if (board[y][x]) { drawBlock(ctx, x, y, board[y][x]); } } } } // 绘制单个方块 function drawPiece(piece) { const shape = SHAPES[piece.shape]; for (let y = 0; y < shape.length; y++) { for (let x = 0; x < shape[y].length; x++) { if (shape[y][x]) { drawBlock(ctx, piece.x + x, piece.y + y, piece.shape); } } } } // 绘制下一个方块预览 function drawNextPiece() { nextCtx.clearRect(0, 0, nextCanvas.width, nextCanvas.height); nextCtx.fillStyle = 'rgba(10, 15, 35, 0.9)'; nextCtx.fillRect(0, 0, nextCanvas.width, nextCanvas.height); const shape = SHAPES[nextPiece.shape]; const offsetX = (nextCanvas.width / 2) - (shape[0].length * BLOCK_SIZE / 2); const offsetY = (nextCanvas.height / 2) - (shape.length * BLOCK_SIZE / 2); for (let y = 0; y < shape.length; y++) { for (let x = 0; x < shape[y].length; x++) { if (shape[y][x]) { drawBlock(nextCtx, x, y, nextPiece.shape, offsetX, offsetY); } } } } // 绘制单个方块 function drawBlock(context, x, y, colorIndex, offsetX = 0, offsetY = 0) { const color = COLORS[colorIndex]; context.fillStyle = color; context.fillRect(offsetX + x * BLOCK_SIZE, offsetY + y * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE); context.strokeStyle = '#000'; context.lineWidth = 2; context.strokeRect(offsetX + x * BLOCK_SIZE, offsetY + y * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE); // 添加内部高光效果 context.fillStyle = 'rgba(255, 255, 255, 0.2)'; context.fillRect(offsetX + x * BLOCK_SIZE, offsetY + y * BLOCK_SIZE, BLOCK_SIZE - 2, 2); context.fillRect(offsetX + x * BLOCK_SIZE, offsetY + y * BLOCK_SIZE, 2, BLOCK_SIZE - 2); // 添加内部阴影效果 context.fillStyle = 'rgba(0, 0, 0, 0.2)'; context.fillRect(offsetX + x * BLOCK_SIZE + 2, offsetY + y * BLOCK_SIZE + BLOCK_SIZE - 2, BLOCK_SIZE - 2, 2); context.fillRect(offsetX + x * BLOCK_SIZE + BLOCK_SIZE - 2, offsetY + y * BLOCK_SIZE + 2, 2, BLOCK_SIZE - 2); } // 下落方块 function dropPiece() { currentPiece.y++; if (checkCollision()) { currentPiece.y--; mergePiece(); clearLines(); createPiece(); } dropCounter = 0; } // 移动方块 function movePiece(direction) { currentPiece.x += direction; if (checkCollision()) { currentPiece.x -= direction; } } // 旋转方块 function rotatePiece() { const originalShape = SHAPES[currentPiece.shape]; const rotated = []; // 创建旋转后的形状 for (let i = 0; i < originalShape[0].length; i++) { rotated[i] = []; for (let j = originalShape.length - 1; j >= 0; j--) { rotated[i].push(originalShape[j][i]); } } // 临时保存原始形状 const original = SHAPES[currentPiece.shape]; // 替换为旋转后的形状 SHAPES[currentPiece.shape] = rotated; // 检查碰撞,如果有碰撞则恢复原始形状 if (checkCollision()) { SHAPES[currentPiece.shape] = original; } } // 硬降(直接落到底部) function hardDrop() { while (!checkCollision()) { currentPiece.y++; } currentPiece.y--; mergePiece(); clearLines(); createPiece(); } // 检查碰撞 function checkCollision() { const shape = SHAPES[currentPiece.shape]; for (let y = 0; y < shape.length; y++) { for (let x = 0; x < shape[y].length; x++) { if (shape[y][x] === 0) continue; const newX = currentPiece.x + x; const newY = currentPiece.y + y; if ( newX < 0 || newX >= COLS || newY >= ROWS || (newY >= 0 && board[newY][newX]) ) { return true; } } } return false; } // 合并方块到游戏板 function mergePiece() { const shape = SHAPES[currentPiece.shape]; for (let y = 0; y < shape.length; y++) { for (let x = 0; x < shape[y].length; x++) { if (shape[y][x]) { if (currentPiece.y + y >= 0) { board[currentPiece.y + y][currentPiece.x + x] = currentPiece.shape; } } } } } // 清除完整的行 function clearLines() { let linesCleared = 0; for (let y = ROWS - 1; y >= 0; y--) { if (board[y].every(value => value !== 0)) { // 移除该行 board.splice(y, 1); // 在顶部添加新行 board.unshift(Array(COLS).fill(0)); linesCleared++; y++; // 重新检查当前行(因为下移了一行) } } if (linesCleared > 0) { // 更新分数 lines += linesCleared; score += [40, 100, 300, 1200][linesCleared - 1] * level; // 每清除10行提高一个等级 level = Math.floor(lines / 10) + 1; // 根据等级调整下落速度 dropInterval = Math.max(100, 1000 - (level - 1) * 100); // 更新显示 updateStats(); } } // 更新分数显示 function updateStats() { document.getElementById('score').textContent = score; document.getElementById('lines').textContent = lines; document.getElementById('level').textContent = level; } // 处理键盘事件 function handleKeyPress(event) { if (gameOver || isPaused) return; switch (event.keyCode) { case 37: // 左箭头 movePiece(-1); break; case 39: // 右箭头 movePiece(1); break; case 40: // 下箭头 dropPiece(); break; case 38: // 上箭头 rotatePiece(); break; case 32: // 空格 hardDrop(); break; case 80: // P键 togglePause(); break; } } // 页面加载完成后初始化游戏 window.addEventListener('load', init); </script> </body> </html>

游戏功能说明

这个俄罗斯方块游戏包含以下功能:

  1. 核心游戏机制

    • 七种经典俄罗斯方块形状(I、J、L、O、S、T、Z)
    • 方块旋转、左右移动和加速下落
    • 行消除和得分系统
    • 难度随等级提升(下落速度加快)
  2. 游戏界面

    • 主游戏区域(10×20网格)
    • 下一个方块预览
    • 分数、行数和等级显示
    • 游戏控制说明
    • 游戏结束画面
  3. 控制方式

    • 左/右箭头:左右移动方块
    • 上箭头:旋转方块
    • 下箭头:加速下落
    • 空格键:直接落到底部
    • P键:暂停/继续游戏
  4. 游戏操作按钮

    • 开始游戏
    • 暂停游戏
    • 重新开始
  5. 视觉效果

    • 渐变背景和半透明元素
    • 方块高光和阴影效果
    • 响应式设计(适配不同屏幕尺寸)

将上述代码复制到HTML文件中,直接在浏览器中打开即可开始游戏!