扫雷游戏,作为经典的电脑游戏之一,玩家通过点击空白格子来揭示地雷周围的数字,目的是避免触发地雷。虽然规则看似简单,但背后涉及到复杂的游戏逻辑,比如地雷的随机生成、周围数字的计算和格子的揭示等。每次点击后,玩家需要依靠周围数字的信息,进行推理和判断,寻找安全的格子。
过去,开发一个扫雷游戏需要编写复杂的地雷生成算法、格子状态管理、点击事件响应等代码,这对于开发者来说无疑是一项挑战。不过,使用 Trae IDE,所有的复杂逻辑和细节处理都由系统自动完成。接下来,我将分享如何通过 Trae 快速生成一个扫雷游戏,轻松实现经典的逻辑挑战。
💡 我的需求其实很简单
我的需求非常明确:制作一个扫雷游戏,功能要求如下:
- 随机生成地雷:游戏开始时,在棋盘上随机生成若干个地雷。
- 揭示空白格子:玩家点击空白格子,显示该格子周围地雷的数量。
- 避免触雷:玩家需要通过逻辑推理,避免点击到地雷所在的格子。
- 简洁的UI:游戏界面简洁,操作直观,玩家可以轻松玩转扫雷。
虽然游戏规则非常简单,但要实现地雷随机生成、空白格子揭示、点击响应等功能,手动编写这些逻辑依然需要一定的工作量。
✨ Trae 如何理解需求并生成代码?
我只需要在 Trae 中输入一句话:
"生成扫雷游戏,玩家点击空白格子,避免触发地雷。"

Trae 会自动解析我的需求,并生成完整的扫雷游戏代码,包括:
- 地雷生成:游戏在棋盘上随机生成地雷,并确保地雷的数量符合设置的要求。
- 空白格子揭示:当玩家点击空白格子时,系统会自动显示该格子周围的地雷数量。若格子周围没有地雷,则继续揭示相邻空白格子,直到达到游戏规则。
- 游戏规则:玩家点击到地雷所在的格子,游戏结束,显示游戏失败的提示。
- 简洁的UI设计:游戏界面设计简洁,格子的点击和揭示效果流畅,玩家能够轻松进行操作。

只需简单的指令,Trae 就能为我自动生成一个完整的扫雷游戏,并处理所有复杂的游戏逻辑。
🧩 游戏操作简便,逻辑清晰
Trae 生成的扫雷游戏操作非常简便。玩家只需要点击空白格子,系统会揭示该格子周围的数字。如果格子周围没有地雷,系统会继续自动揭示相邻的格子。如果玩家点击到地雷所在的格子,游戏会结束并显示"游戏失败"提示。
每个格子的揭示效果都非常流畅,点击后的反应及时,让玩家能够快速了解每一步的进展。此外,系统会自动计算每个格子周围地雷的数量,并显示在该格子上,帮助玩家判断哪些地方安全。
🛠 游戏拓展,功能轻松加
尽管 Trae 生成的扫雷游戏已经非常完善,但它也支持轻松添加更多功能。例如:
- 计时器功能:为游戏增加计时功能,记录玩家完成扫雷的时间,增加游戏的挑战性。
- 难度设置:可以设置不同的难度,调整棋盘的大小和地雷的数量。
- 排行榜功能:记录玩家的成绩,并展示排行榜,增加游戏的竞争性。
- 音效和动画:为点击格子的揭示效果和触雷时加入音效,增加游戏的互动性。
这些新功能都可以通过简单描述,Trae 会自动生成并将其集成到现有的游戏中。
这就是扫雷游戏开发的新体验
通过这次扫雷游戏的开发,我深刻感受到了 Trae 带来的便利。从地雷的随机生成,到格子的揭示和游戏失败的判断,Trae 都能完美地自动化完成。这样,我不需要担心复杂的逻辑实现,而只需专注于游戏设计和细节。
对于独立开发者或小团队来说,Trae 是一个非常高效的工具,它能够帮助你快速完成游戏开发,专注于创意和功能拓展。
结语
如果你也想制作一个经典的扫雷游戏,试试 Trae IDE,输入类似的需求:
"生成扫雷游戏,玩家点击空白格子,避免触发地雷。"
几秒钟内,Trae 就会生成完整的扫雷游戏代码,带有地雷随机生成、格子揭示、点击响应等功能。你可以直接将它嵌入到你的项目中,甚至根据需求继续扩展和优化。
快来体验一下 Trae,让你的扫雷游戏开发变得更加轻松、充满挑战!
html
<!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>