扫雷游戏,作为经典的电脑游戏之一,玩家通过点击空白格子来揭示地雷周围的数字,目的是避免触发地雷。虽然规则看似简单,但背后涉及到复杂的游戏逻辑,比如地雷的随机生成、周围数字的计算和格子的揭示等。每次点击后,玩家需要依靠周围数字的信息,进行推理和判断,寻找安全的格子。
过去,开发一个扫雷游戏需要编写复杂的地雷生成算法、格子状态管理、点击事件响应等代码,这对于开发者来说无疑是一项挑战。不过,使用 Trae IDE,所有的复杂逻辑和细节处理都由系统自动完成。接下来,我将分享如何通过 Trae 快速生成一个扫雷游戏,轻松实现经典的逻辑挑战。
💡 我的需求其实很简单
我的需求非常明确:制作一个扫雷游戏,功能要求如下:
- 随机生成地雷:游戏开始时,在棋盘上随机生成若干个地雷。揭示空白格子:玩家点击空白格子,显示该格子周围地雷的数量。避免触雷:玩家需要通过逻辑推理,避免点击到地雷所在的格子。简洁的UI:游戏界面简洁,操作直观,玩家可以轻松玩转扫雷。
虽然游戏规则非常简单,但要实现地雷随机生成、空白格子揭示、点击响应等功能,手动编写这些逻辑依然需要一定的工作量。
✨ Trae 如何理解需求并生成代码?
我只需要在 Trae 中输入一句话:
“生成扫雷游戏,玩家点击空白格子,避免触发地雷。”
Trae 会自动解析我的需求,并生成完整的扫雷游戏代码,包括:
- 地雷生成:游戏在棋盘上随机生成地雷,并确保地雷的数量符合设置的要求。空白格子揭示:当玩家点击空白格子时,系统会自动显示该格子周围的地雷数量。若格子周围没有地雷,则继续揭示相邻空白格子,直到达到游戏规则。游戏规则:玩家点击到地雷所在的格子,游戏结束,显示游戏失败的提示。简洁的UI设计:游戏界面设计简洁,格子的点击和揭示效果流畅,玩家能够轻松进行操作。
只需简单的指令,Trae 就能为我自动生成一个完整的扫雷游戏,并处理所有复杂的游戏逻辑。
🧩 游戏操作简便,逻辑清晰
Trae 生成的扫雷游戏操作非常简便。玩家只需要点击空白格子,系统会揭示该格子周围的数字。如果格子周围没有地雷,系统会继续自动揭示相邻的格子。如果玩家点击到地雷所在的格子,游戏会结束并显示“游戏失败”提示。
每个格子的揭示效果都非常流畅,点击后的反应及时,让玩家能够快速了解每一步的进展。此外,系统会自动计算每个格子周围地雷的数量,并显示在该格子上,帮助玩家判断哪些地方安全。
🛠 游戏拓展,功能轻松加
尽管 Trae 生成的扫雷游戏已经非常完善,但它也支持轻松添加更多功能。例如:
- 计时器功能:为游戏增加计时功能,记录玩家完成扫雷的时间,增加游戏的挑战性。难度设置:可以设置不同的难度,调整棋盘的大小和地雷的数量。排行榜功能:记录玩家的成绩,并展示排行榜,增加游戏的竞争性。音效和动画:为点击格子的揭示效果和触雷时加入音效,增加游戏的互动性。
这些新功能都可以通过简单描述,Trae 会自动生成并将其集成到现有的游戏中。
这就是扫雷游戏开发的新体验
通过这次扫雷游戏的开发,我深刻感受到了 Trae 带来的便利。从地雷的随机生成,到格子的揭示和游戏失败的判断,Trae 都能完美地自动化完成。这样,我不需要担心复杂的逻辑实现,而只需专注于游戏设计和细节。
对于独立开发者或小团队来说,Trae 是一个非常高效的工具,它能够帮助你快速完成游戏开发,专注于创意和功能拓展。
结语
如果你也想制作一个经典的扫雷游戏,试试 Trae IDE,输入类似的需求:
“生成扫雷游戏,玩家点击空白格子,避免触发地雷。”
几秒钟内,Trae 就会生成完整的扫雷游戏代码,带有地雷随机生成、格子揭示、点击响应等功能。你可以直接将它嵌入到你的项目中,甚至根据需求继续扩展和优化。
快来体验一下 Trae,让你的扫雷游戏开发变得更加轻松、充满挑战!
<!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 { font-family: 'Arial', sans-serif; background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%); display: flex; justify-content: center; align-items: center; min-height: 100vh; color: #333; } .game-container { background-color: #fff; border-radius: 10px; box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2); padding: 20px; width: 90%; max-width: 500px; } .game-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; padding-bottom: 15px; border-bottom: 1px solid #eee; } .game-info { display: flex; gap: 15px; } .mines-counter, .timer { background-color: #333; color: #ff0000; font-family: 'Courier New', monospace; font-size: 24px; font-weight: bold; padding: 5px 10px; border-radius: 5px; min-width: 80px; text-align: center; } .difficulty-selector { display: flex; justify-content: center; margin-bottom: 20px; } .difficulty-btn { background-color: #e0e0e0; border: none; padding: 8px 15px; margin: 0 5px; border-radius: 5px; cursor: pointer; transition: all 0.2s; font-weight: bold; } .difficulty-btn:hover { background-color: #d0d0d0; } .difficulty-btn.active { background-color: #4a6fa5; color: white; } .game-board { display: grid; grid-template-columns: repeat(9, 1fr); gap: 2px; margin: 0 auto; user-select: none; } .cell { aspect-ratio: 1 / 1; background-color: #bdbdbd; border: 2px solid; border-color: #f5f5f5 #7b7b7b #7b7b7b #f5f5f5; display: flex; justify-content: center; align-items: center; font-weight: bold; font-size: 18px; cursor: pointer; } .cell:hover { filter: brightness(1.1); } .cell.revealed { background-color: #d9d9d9; border-color: #bdbdbd; border-width: 1px; } .cell.mine { background-color: #ff4d4d; } .cell.flagged { background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M4,2H6V4H10V6H6V12H10V14H6V20H4V14H0V12H4V6H0V4H4V2Z" fill="%23ff0000"/></svg>'); background-repeat: no-repeat; background-position: center; background-size: 60%; } .cell.question { background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12,2C6.48,2 2,6.48 2,12C2,17.52 6.48,22 12,22C17.52,22 22,17.52 22,12C22,6.48 17.52,2 12,2ZM13,19H11V17H13V19ZM15.07,11.25L14.17,12.17C13.45,12.9 13,13.5 13,15H11V14.5C11,13.4 11.45,12.4 12.17,11.67L13.41,10.41C13.78,10.05 14,9.55 14,9C14,7.9 13.1,7 12,7C10.9,7 10,7.9 10,9H8C8,6.79 9.79,5 12,5C14.21,5 16,6.79 16,9C16,9.88 15.64,10.68 15.07,11.25Z" fill="%23333"/></svg>'); background-repeat: no-repeat; background-position: center; background-size: 60%; } .cell.mine-revealed { background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><circle cx="12" cy="12" r="10" fill="%23333"/><circle cx="12" cy="12" r="8" fill="%23000"/><line x1="6" y1="6" x2="18" y2="18" stroke="%23fff" stroke-width="2"/><line x1="6" y1="18" x2="18" y2="6" stroke="%23fff" stroke-width="2"/><line x1="12" y1="2" x2="12" y2="22" stroke="%23fff" stroke-width="2"/><line x1="2" y1="12" x2="22" y2="12" stroke="%23fff" stroke-width="2"/></svg>'); background-repeat: no-repeat; background-position: center; background-size: 70%; } .cell.mine-wrong { background-color: #ff4d4d; background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><circle cx="12" cy="12" r="10" fill="%23333"/><circle cx="12" cy="12" r="8" fill="%23000"/><line x1="6" y1="6" x2="18" y2="18" stroke="%23fff" stroke-width="2"/><line x1="6" y1="18" x2="18" y2="6" stroke="%23fff" stroke-width="2"/><line x1="12" y1="2" x2="12" y2="22" stroke="%23fff" stroke-width="2"/><line x1="2" y1="12" x2="22" y2="12" stroke="%23fff" stroke-width="2"/></svg>'); background-repeat: no-repeat; background-position: center; background-size: 70%; } .number-1 { color: #0000ff; } .number-2 { color: #008000; } .number-3 { color: #ff0000; } .number-4 { color: #000080; } .number-5 { color: #800000; } .number-6 { color: #008080; } .number-7 { color: #000000; } .number-8 { color: #808080; } .controls { display: flex; justify-content: space-between; margin-top: 20px; padding-top: 15px; border-top: 1px solid #eee; } .btn { background-color: #4a6fa5; color: white; border: none; padding: 10px 20px; border-radius: 5px; cursor: pointer; transition: all 0.2s; font-weight: bold; } .btn:hover { background-color: #3a5a80; } .btn:active { transform: scale(0.98); } .restart-btn { background-color: #f5f5f5; border: 2px solid #bdbdbd; border-radius: 50%; width: 40px; height: 40px; display: flex; justify-content: center; align-items: center; cursor: pointer; font-size: 24px; transition: all 0.2s; } .restart-btn:hover { background-color: #e0e0e0; } .restart-btn.sad { background-color: #ffcccc; } .restart-btn.happy { background-color: #ccffcc; } .modal { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0, 0, 0, 0.7); display: flex; justify-content: center; align-items: center; z-index: 1000; opacity: 0; visibility: hidden; transition: all 0.3s; } .modal.active { opacity: 1; visibility: visible; } .modal-content { background-color: white; padding: 30px; border-radius: 10px; text-align: center; max-width: 90%; width: 400px; transform: scale(0.8); transition: transform 0.3s; } .modal.active .modal-content { transform: scale(1); } .modal h2 { margin-bottom: 20px; color: #333; } .modal p { margin-bottom: 30px; color: #666; line-height: 1.5; } .modal-buttons { display: flex; justify-content: center; gap: 15px; } .help-btn { background-color: transparent; border: none; color: #4a6fa5; cursor: pointer; font-size: 16px; padding: 5px; } .help-btn:hover { text-decoration: underline; } @media (max-width: 500px) { .game-container { padding: 15px; width: 95%; } .mines-counter, .timer { font-size: 18px; min-width: 60px; } .cell { font-size: 14px; } .difficulty-btn { padding: 6px 10px; font-size: 14px; } .btn { padding: 8px 15px; font-size: 14px; } } </style></head><body> <div class="game-container"> <div class="game-header"> <div class="mines-counter" id="mines-counter">10</div> <div class="restart-btn" id="restart-btn">😊</div> <div class="timer" id="timer">000</div> </div> <div class="difficulty-selector"> <button class="difficulty-btn active" data-difficulty="beginner">初级</button> <button class="difficulty-btn" data-difficulty="intermediate">中级</button> <button class="difficulty-btn" data-difficulty="expert">高级</button> </div> <div class="game-board" id="game-board"> <!-- 游戏格子将由JS动态生成 --> </div> <div class="controls"> <button class="help-btn" id="help-btn">游戏规则</button> <button class="btn" id="new-game-btn">新游戏</button> </div> </div> <div class="modal" id="win-modal"> <div class="modal-content"> <h2>恭喜你赢了!</h2> <p>你成功找出了所有地雷!</p> <p>用时: <span id="win-time">0</span> 秒</p> <div class="modal-buttons"> <button class="btn" id="win-new-game-btn">新游戏</button> </div> </div> </div> <div class="modal" id="lose-modal"> <div class="modal-content"> <h2>游戏结束</h2> <p>很遗憾,你触发了地雷!</p> <div class="modal-buttons"> <button class="btn" id="lose-new-game-btn">再试一次</button> </div> </div> </div> <div class="modal" id="help-modal"> <div class="modal-content"> <h2>游戏规则</h2> <p> 1. 点击格子揭开它<br> 2. 数字表示周围8个格子中的地雷数量<br> 3. 右键点击可以标记地雷(旗子)<br> 4. 再次右键点击可以标记为问号<br> 5. 第三次右键点击取消标记<br> 6. 避免点到地雷,标记出所有地雷即可获胜 </p> <div class="modal-buttons"> <button class="btn" id="close-help-btn">了解了</button> </div> </div> </div> <script> // 获取DOM元素 const gameBoard = document.getElementById('game-board'); const minesCounter = document.getElementById('mines-counter'); const timerElement = document.getElementById('timer'); const restartBtn = document.getElementById('restart-btn'); const newGameBtn = document.getElementById('new-game-btn'); const difficultyBtns = document.querySelectorAll('.difficulty-btn'); const helpBtn = document.getElementById('help-btn'); const winModal = document.getElementById('win-modal'); const loseModal = document.getElementById('lose-modal'); const helpModal = document.getElementById('help-modal'); const winNewGameBtn = document.getElementById('win-new-game-btn'); const loseNewGameBtn = document.getElementById('lose-new-game-btn'); const closeHelpBtn = document.getElementById('close-help-btn'); const winTimeElement = document.getElementById('win-time'); // 游戏配置 const difficulties = { beginner: { rows: 9, cols: 9, mines: 10 }, intermediate: { rows: 16, cols: 16, mines: 40 }, expert: { rows: 16, cols: 30, mines: 99 } }; // 游戏变量 let currentDifficulty = 'beginner'; let board = []; let minesCount; let flagsCount = 0; let revealedCount = 0; let gameStarted = false; let gameOver = false; let timer; let seconds = 0; let firstClick = true; // 初始化游戏 function initGame() { // 重置游戏状态 board = []; gameStarted = false; gameOver = false; firstClick = true; flagsCount = 0; revealedCount = 0; seconds = 0; clearInterval(timer); timerElement.textContent = '000'; restartBtn.textContent = '😊'; restartBtn.classList.remove('sad', 'happy'); // 获取当前难度的配置 const { rows, cols, mines } = difficulties[currentDifficulty]; minesCount = mines; minesCounter.textContent = minesCount; // 设置游戏板样式 gameBoard.style.gridTemplateColumns = `repeat(${cols}, 1fr)`; gameBoard.innerHTML = ''; // 创建格子 for (let row = 0; row < rows; row++) { board[row] = []; for (let col = 0; col < cols; col++) { const cell = document.createElement('div'); cell.className = 'cell'; cell.dataset.row = row; cell.dataset.col = col; // 添加点击事件 cell.addEventListener('click', () => handleCellClick(row, col)); cell.addEventListener('contextmenu', (e) => { e.preventDefault(); handleRightClick(row, col); }); gameBoard.appendChild(cell); // 初始化格子状态 board[row][col] = { element: cell, isMine: false, isRevealed: false, isFlagged: false, isQuestion: false, neighborMines: 0 }; } } } // 生成地雷 function generateMines(firstRow, firstCol) { const { rows, cols, mines } = difficulties[currentDifficulty]; let minesPlaced = 0; // 确保第一次点击的位置及其周围没有地雷 const safeZone = []; for (let r = Math.max(0, firstRow - 1); r <= Math.min(rows - 1, firstRow + 1); r++) { for (let c = Math.max(0, firstCol - 1); c <= Math.min(cols - 1, firstCol + 1); c++) { safeZone.push(`${r},${c}`); } } // 随机放置地雷 while (minesPlaced < mines) { const row = Math.floor(Math.random() * rows); const col = Math.floor(Math.random() * cols); const key = `${row},${col}`; // 确保不在安全区域内放置地雷 if (!safeZone.includes(key) && !board[row][col].isMine) { board[row][col].isMine = true; minesPlaced++; } } // 计算每个格子周围的地雷数 for (let row = 0; row < rows; row++) { for (let col = 0; col < cols; col++) { if (!board[row][col].isMine) { board[row][col].neighborMines = countNeighborMines(row, col); } } } } // 计算周围的地雷数 function countNeighborMines(row, col) { let count = 0; const { rows, cols } = difficulties[currentDifficulty]; for (let r = Math.max(0, row - 1); r <= Math.min(rows - 1, row + 1); r++) { for (let c = Math.max(0, col - 1); c <= Math.min(cols - 1, col + 1); c++) { if (r === row && c === col) continue; if (board[r][c].isMine) count++; } } return count; } // 处理格子点击 function handleCellClick(row, col) { if (gameOver || board[row][col].isRevealed || board[row][col].isFlagged) return; // 第一次点击时生成地雷 if (firstClick) { generateMines(row, col); startTimer(); firstClick = false; } // 揭开格子 revealCell(row, col); // 检查游戏状态 checkGameStatus(); } // 处理右键点击(标记地雷) function handleRightClick(row, col) { if (gameOver || board[row][col].isRevealed) return; const cell = board[row][col]; // 开始计时(如果是第一次操作) if (firstClick) { generateMines(row, col); startTimer(); firstClick = false; } // 循环切换:无标记 -> 旗子 -> 问号 -> 无标记 if (!cell.isFlagged && !cell.isQuestion) { // 设置旗子 cell.isFlagged = true; cell.element.classList.add('flagged'); flagsCount++; } else if (cell.isFlagged) { // 设置问号 cell.isFlagged = false; cell.isQuestion = true; cell.element.classList.remove('flagged'); cell.element.classList.add('question'); flagsCount--; } else { // 移除标记 cell.isQuestion = false; cell.element.classList.remove('question'); } // 更新地雷计数器 updateMinesCounter(); // 检查游戏状态 checkGameStatus(); } // 揭开格子 function revealCell(row, col) { const cell = board[row][col]; // 如果已经揭开或已标记,则忽略 if (cell.isRevealed || cell.isFlagged) return; // 标记为已揭开 cell.isRevealed = true; cell.element.classList.add('revealed'); cell.element.classList.remove('question'); revealedCount++; // 如果是地雷,游戏结束 if (cell.isMine) { gameOver = true; cell.element.classList.add('mine-revealed'); revealAllMines(); endGame(false); return; } // 显示周围地雷数 if (cell.neighborMines > 0) { cell.element.textContent = cell.neighborMines; cell.element.classList.add(`number-${cell.neighborMines}`); } else { // 如果周围没有地雷,自动揭开周围的格子 const { rows, cols } = difficulties[currentDifficulty]; for (let r = Math.max(0, row - 1); r <= Math.min(rows - 1, row + 1); r++) { for (let c = Math.max(0, col - 1); c <= Math.min(cols - 1, col + 1); c++) { if (r === row && c === col) continue; revealCell(r, c); } } } } // 揭开所有地雷 function revealAllMines() { const { rows, cols } = difficulties[currentDifficulty]; for (let row = 0; row < rows; row++) { for (let col = 0; col < cols; col++) { const cell = board[row][col]; if (cell.isMine && !cell.isRevealed) { cell.element.classList.add('mine-revealed'); } // 标记错误的旗子 if (cell.isFlagged && !cell.isMine) { cell.element.classList.add('mine-wrong'); } } } } // 更新地雷计数器 function updateMinesCounter() { const remainingMines = minesCount - flagsCount; minesCounter.textContent = remainingMines < 0 ? '000' : remainingMines; } // 开始计时器 function startTimer() { gameStarted = true; timer = setInterval(() => { seconds++; timerElement.textContent = seconds.toString().padStart(3, '0'); if (seconds >= 999) { clearInterval(timer); } }, 1000); } // 检查游戏状态 function checkGameStatus() { if (gameOver) return; const { rows, cols, mines } = difficulties[currentDifficulty]; const totalCells = rows * cols; // 检查是否获胜(所有非地雷格子都已揭开) if (revealedCount === totalCells - mines) { gameOver = true; endGame(true); } } // 结束游戏 function endGame(isWin) { clearInterval(timer); if (isWin) { // 标记所有地雷 const { rows, cols } = difficulties[currentDifficulty]; for (let row = 0; row < rows; row++) { for (let col = 0; col < cols; col++) { if (board[row][col].isMine && !board[row][col].isFlagged) { board[row][col].isFlagged = true; board[row][col].element.classList.add('flagged'); } } } restartBtn.textContent = '😎'; restartBtn.classList.add('happy'); winTimeElement.textContent = seconds; setTimeout(() => { winModal.classList.add('active'); }, 500); } else { restartBtn.textContent = '😵'; restartBtn.classList.add('sad'); setTimeout(() => { loseModal.classList.add('active'); }, 500); } } // 切换难度 function changeDifficulty(difficulty) { currentDifficulty = difficulty; // 更新按钮状态 difficultyBtns.forEach(btn => { if (btn.dataset.difficulty === difficulty) { btn.classList.add('active'); } else { btn.classList.remove('active'); } }); // 重新初始化游戏 initGame(); } // 事件监听 difficultyBtns.forEach(btn => { btn.addEventListener('click', () => { changeDifficulty(btn.dataset.difficulty); }); }); restartBtn.addEventListener('click', initGame); newGameBtn.addEventListener('click', initGame); winNewGameBtn.addEventListener('click', () => { winModal.classList.remove('active'); initGame(); }); loseNewGameBtn.addEventListener('click', () => { loseModal.classList.remove('active'); initGame(); }); helpBtn.addEventListener('click', () => { helpModal.classList.add('active'); }); closeHelpBtn.addEventListener('click', () => { helpModal.classList.remove('active'); }); // 初始化游戏 initGame(); </script></body></html>
