完整源碼在本文結尾處
一、游戲概述
掃雷是一款經典的益智游戲,玩家需要在不觸發地雷的情況下揭開所有安全格子。本教程將帶你從零開始開發一個具有精美界面和動畫效果的掃雷游戲,包含難度選擇、棋盤大小調整等高級功能。
二、游戲核心功能
- 三種難度級別:初級(9×9)、中級(16×16)、高級(16×30)
- 棋盤大小調整:小、中、大三種尺寸
- 計時系統:記錄游戲用時
- 地雷計數器:顯示剩余地雷數量
- 標記系統:右鍵標記可疑地雷位置
- 動畫效果:格子揭示、地雷爆炸、勝利慶祝等動畫
三、開發步驟詳解
- 游戲數據結構設計
// 游戲配置
const DIFFICULTY = {beginner: { rows: 9, cols: 9, mines: 10 },intermediate: { rows: 16, cols: 16, mines: 40 },expert: { rows: 16, cols: 30, mines: 99 }
};// 尺寸因子
const SIZE_FACTOR = {small: 0.8,medium: 1.0,large: 1.2
};// 游戲狀態
let gameConfig = { ...DIFFICULTY.beginner, sizeFactor: SIZE_FACTOR.small };
let board = []; // 存儲每個格子的值(-1表示地雷,0-8表示周圍地雷數)
let revealed = []; // 記錄格子是否被揭開
let flagged = []; // 記錄格子是否被標記
let mines = []; // 存儲所有地雷位置
- 初始化游戲
function initGame() {// 重置游戲狀態clearInterval(timerInterval);timer = 0;gameOver = false;gameWon = false;firstClick = true;// 創建棋盤數據結構createBoard();// 渲染棋盤到DOMrenderBoard();
}function createBoard() {// 初始化二維數組for (let i = 0; i < gameConfig.rows; i++) {board[i] = [];revealed[i] = [];flagged[i] = [];for (let j = 0; j < gameConfig.cols; j++) {board[i][j] = 0;revealed[i][j] = false;flagged[i][j] = false;}}
}
- 渲染棋盤
function renderBoard() {gridElement.innerHTML = '';gridElement.style.gridTemplateColumns = `repeat(${gameConfig.cols}, 1fr)`;// 應用尺寸因子const cellSize = Math.floor(30 * gameConfig.sizeFactor);document.documentElement.style.setProperty('--cell-size', `${cellSize}px`);for (let i = 0; i < gameConfig.rows; i++) {for (let j = 0; j < gameConfig.cols; j++) {const cell = document.createElement('div');cell.className = 'cell';cell.dataset.row = i;cell.dataset.col = j;// 添加點擊事件cell.addEventListener('click', () => handleCellClick(i, j));cell.addEventListener('contextmenu', (e) => {e.preventDefault();handleRightClick(i, j);});gridElement.appendChild(cell);}}
}
- 放置地雷(確保第一次點擊安全)
function placeMines(firstRow, firstCol) {mines = [];let minesPlaced = 0;// 確保第一次點擊周圍沒有地雷const safeCells = [];for (let i = -1; i <= 1; i++) {for (let j = -1; j <= 1; j++) {const newRow = firstRow + i;const newCol = firstCol + j;if (newRow >= 0 && newRow < gameConfig.rows && newCol >= 0 && newCol < gameConfig.cols) {safeCells.push(`${newRow},${newCol}`);}}}// 隨機放置地雷while (minesPlaced < gameConfig.mines) {const row = Math.floor(Math.random() * gameConfig.rows);const col = Math.floor(Math.random() * gameConfig.cols);// 跳過第一次點擊及其周圍的格子if (row === firstRow && col === firstCol) continue;if (safeCells.includes(`${row},${col}`)) continue;if (board[row][col] === -1) continue;board[row][col] = -1;mines.push({ row, col });minesPlaced++;// 更新周圍格子的數字for (let i = -1; i <= 1; i++) {for (let j = -1; j <= 1; j++) {const newRow = row + i;const newCol = col + j;if (newRow >= 0 && newRow < gameConfig.rows && newCol >= 0 && newCol < gameConfig.cols && board[newRow][newCol] !== -1) {board[newRow][newCol]++;}}}}
}
- 處理格子點擊
function handleCellClick(row, col) {if (gameOver || gameWon || flagged[row][col]) return;// 第一次點擊放置地雷if (firstClick) {placeMines(row, col);firstClick = false;// 開始計時timerInterval = setInterval(() => {timer++;timerElement.textContent = timer;}, 1000);}// 如果點擊到地雷if (board[row][col] === -1) {revealMines();gameOver = true;statusElement.textContent = "游戲結束!你踩到地雷了 💥";statusElement.classList.add("game-over");clearInterval(timerInterval);return;}// 揭示格子revealCell(row, col);// 檢查勝利條件checkWin();
}function revealCell(row, col) {if (revealed[row][col] || flagged[row][col]) return;revealed[row][col] = true;const cell = document.querySelector(`.cell[data-row="${row}"][data-col="${col}"]`);cell.classList.add('revealed');if (board[row][col] > 0) {cell.textContent = board[row][col];cell.classList.add(`num-${board[row][col]}`);} else if (board[row][col] === 0) {// 遞歸揭示周圍格子for (let i = -1; i <= 1; i++) {for (let j = -1; j <= 1; j++) {const newRow = row + i;const newCol = col + j;if (newRow >= 0 && newRow < gameConfig.rows && newCol >= 0 && newCol < gameConfig.cols) {revealCell(newRow, newCol);}}}}
}
- 右鍵標記功能
function handleRightClick(row, col) {if (gameOver || gameWon || revealed[row][col]) return;// 切換旗幟狀態flagged[row][col] = !flagged[row][col];flagCount += flagged[row][col] ? 1 : -1;// 更新UIconst cell = document.querySelector(`.cell[data-row="${row}"][data-col="${col}"]`);if (flagged[row][col]) {cell.classList.add('flagged');cell.textContent = '🚩';} else {cell.classList.remove('flagged');cell.textContent = '';}// 更新剩余地雷計數remainingMines = gameConfig.mines - flagCount;mineCountElement.textContent = remainingMines;// 檢查勝利條件checkWin();
}
- 勝利條件檢查
function checkWin() {// 檢查是否所有非地雷格子都被揭示let allRevealed = true;for (let i = 0; i < gameConfig.rows; i++) {for (let j = 0; j < gameConfig.cols; j++) {if (board[i][j] !== -1 && !revealed[i][j]) {allRevealed = false;break;}}if (!allRevealed) break;}// 檢查是否所有地雷都被正確標記let allMinesFlagged = true;mines.forEach(mine => {if (!flagged[mine.row][mine.col]) {allMinesFlagged = false;}});if (allRevealed || allMinesFlagged) {gameWon = true;clearInterval(timerInterval);statusElement.textContent = `恭喜獲勝!用時 ${timer} 秒 🎉`;statusElement.classList.add("win");revealMines();}
}
四、關鍵CSS樣式解析
- 格子基礎樣式
.cell {width: var(--cell-size, 30px);height: var(--cell-size, 30px);background: linear-gradient(145deg, #95a5a6, #7f8c8d);border: 2px outset #ecf0f1;display: flex;align-items: center;justify-content: center;cursor: pointer;transition: all 0.2s ease;border-radius: 4px;
}.cell:hover:not(.revealed) {background: linear-gradient(145deg, #bdc3c7, #95a5a6);transform: scale(0.95);
}
- 動畫效果
/* 揭示動畫 */
.revealed {animation: reveal 0.3s ease;
}@keyframes reveal {0% { transform: scale(1); opacity: 0.8; }50% { transform: scale(0.95); opacity: 0.9; }100% { transform: scale(0.97); opacity: 1; }
}/* 地雷爆炸動畫 */
.mine {animation: mineExplode 0.5s ease;
}@keyframes mineExplode {0% { transform: scale(1); }50% { transform: scale(1.2); }100% { transform: scale(1); }
}/* 旗幟標記動畫 */
.flagged {animation: flagWave 0.5s ease;
}@keyframes flagWave {0% { transform: rotate(-10deg); }50% { transform: rotate(10deg); }100% { transform: rotate(0); }
}
五、如何擴展游戲
- 添加關卡系統:設計不同主題的關卡(沙漠、雪地、太空等)
- 實現存檔功能:使用localStorage保存游戲進度
- 添加音效:為點擊、爆炸、勝利等事件添加音效
- 設計成就系統:根據游戲表現解鎖成就
- 添加多人模式:實現玩家間的競爭或合作模式
六、開發小貼士
- 測試驅動開發:先編寫測試用例再實現功能
- 模塊化設計:將游戲拆分為獨立模塊(渲染、邏輯、事件處理)
- 性能優化:對于大型棋盤使用虛擬滾動技術
- 響應式設計:確保在不同設備上都有良好的體驗
- 代碼注釋:為復雜邏輯添加詳細注釋
七、總結
通過本教程,你已經學會了如何開發一個功能完整的掃雷游戲。記住,游戲開發就像掃雷一樣——需要耐心、策略和一點冒險精神!當你遇到"地雷"(bug)時,不要灰心,標記它、分析它,然后優雅地解決它。
現在,快去創建你自己的掃雷游戲吧!如果你在開發過程中遇到任何問題,記得程序員休閑群QQ:708877645里有眾多掃雷高手可以幫你排雷!💣??🚩
完整源代碼
<!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>/* 所有CSS樣式保持不變 */* {margin: 0;padding: 0;box-sizing: border-box;font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;}body {display: flex;justify-content: center;align-items: center;min-height: 100vh;background: linear-gradient(135deg, #1a2a6c, #b21f1f, #fdbb2d);padding: 20px;}.game-container {background: rgba(255, 255, 255, 0.9);border-radius: 20px;box-shadow: 0 15px 30px rgba(0, 0, 0, 0.3);padding: 30px;width: 100%;max-width: 800px;text-align: center;transform: translateY(0);transition: transform 0.3s ease;}.game-container:hover {transform: translateY(-5px);}.game-title {font-size: 2.5rem;color: #2c3e50;margin-bottom: 20px;text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.1);animation: pulse 2s infinite;}@keyframes pulse {0% { transform: scale(1); }50% { transform: scale(1.03); }100% { transform: scale(1); }}.controls {display: flex;justify-content: center;gap: 15px;margin-bottom: 25px;flex-wrap: wrap;}.control-group {background: #f8f9fa;border-radius: 15px;padding: 15px;box-shadow: 0 5px 15px rgba(0, 0, 0, 0.05);}.control-title {font-size: 1.2rem;margin-bottom: 10px;color: #3498db;}.difficulty-btn, .size-btn, .new-game-btn {padding: 12px 20px;border: none;border-radius: 50px;cursor: pointer;font-weight: bold;font-size: 1rem;transition: all 0.3s ease;box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);margin: 5px;}.difficulty-btn {background: linear-gradient(135deg, #3498db, #2c3e50);color: white;}.size-btn {background: linear-gradient(135deg, #2ecc71, #27ae60);color: white;}.new-game-btn {background: linear-gradient(135deg, #e74c3c, #c0392b);color: white;font-size: 1.1rem;padding: 15px 25px;}.difficulty-btn:hover, .size-btn:hover, .new-game-btn:hover {transform: translateY(-3px);box-shadow: 0 6px 12px rgba(0, 0, 0, 0.15);}.difficulty-btn.active, .size-btn.active {transform: scale(1.05);box-shadow: 0 0 15px rgba(52, 152, 219, 0.6);animation: activeGlow 1.5s infinite alternate;}@keyframes activeGlow {0% { box-shadow: 0 0 10px rgba(52, 152, 219, 0.6); }100% { box-shadow: 0 0 20px rgba(52, 152, 219, 0.8); }}.status-bar {display: flex;justify-content: space-between;margin-bottom: 20px;background: linear-gradient(to right, #3498db, #2c3e50);border-radius: 50px;padding: 15px 25px;color: white;box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2);}.status-item {font-size: 1.2rem;font-weight: bold;}.grid-container {overflow: auto;margin: 0 auto;padding: 10px;background: #2c3e50;border-radius: 15px;box-shadow: inset 0 0 20px rgba(0, 0, 0, 0.3);}.grid {display: grid;gap: 2px;margin: 0 auto;background: #34495e;border-radius: 10px;padding: 5px;}.cell {width: var(--cell-size, 30px);height: var(--cell-size, 30px);background: linear-gradient(145deg, #95a5a6, #7f8c8d);border: 2px outset #ecf0f1;display: flex;align-items: center;justify-content: center;cursor: pointer;font-weight: bold;font-size: 1.1rem;transition: all 0.2s ease;user-select: none;border-radius: 4px;}.cell:hover:not(.revealed) {background: linear-gradient(145deg, #bdc3c7, #95a5a6);transform: scale(0.95);}.revealed {background: #ecf0f1;border: 1px solid #bdc3c7;transform: scale(0.97);animation: reveal 0.3s ease;}@keyframes reveal {0% { transform: scale(1); opacity: 0.8; }50% { transform: scale(0.95); opacity: 0.9; }100% { transform: scale(0.97); opacity: 1; }}.mine {background: #e74c3c !important;animation: mineExplode 0.5s ease;}@keyframes mineExplode {0% { transform: scale(1); }50% { transform: scale(1.2); }100% { transform: scale(1); }}.flagged {background: linear-gradient(145deg, #f1c40f, #f39c12);animation: flagWave 0.5s ease;}@keyframes flagWave {0% { transform: rotate(-10deg); }50% { transform: rotate(10deg); }100% { transform: rotate(0); }}/* 數字顏色 */.num-1 { color: #3498db; }.num-2 { color: #2ecc71; }.num-3 { color: #e74c3c; }.num-4 { color: #9b59b6; }.num-5 { color: #e67e22; }.num-6 { color: #1abc9c; }.num-7 { color: #34495e; }.num-8 { color: #7f8c8d; }.status-message {margin-top: 20px;padding: 15px;border-radius: 10px;font-size: 1.3rem;font-weight: bold;min-height: 50px;display: flex;align-items: center;justify-content: center;transition: all 0.5s ease;background: rgba(236, 240, 241, 0.9);box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);}.game-over {color: #e74c3c;animation: shake 0.5s ease-in-out;}@keyframes shake {0%, 100% { transform: translateX(0); }25% { transform: translateX(-10px); }75% { transform: translateX(10px); }}.win {color: #2ecc71;animation: bounce 0.5s ease-in-out;}@keyframes bounce {0%, 100% { transform: translateY(0); }50% { transform: translateY(-10px); }}.instructions {margin-top: 25px;background: rgba(52, 73, 94, 0.1);padding: 15px;border-radius: 10px;text-align: left;}.instructions h3 {color: #2c3e50;margin-bottom: 10px;}.instructions p {margin-bottom: 8px;color: #34495e;}/* 響應式設計 */@media (max-width: 768px) {.controls {flex-direction: column;align-items: center;}.difficulty-btn, .size-btn {width: 100%;max-width: 250px;}.cell {width: 25px;height: 25px;font-size: 0.9rem;}}@media (max-width: 480px) {.cell {width: 20px;height: 20px;font-size: 0.8rem;}.game-title {font-size: 2rem;}}</style>
</head>
<body><div class="game-container"><h1 class="game-title">程序員休閑群QQ:708877645掃雷</h1><div class="controls"><div class="control-group"><div class="control-title">難度選擇</div><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="control-group"><div class="control-title">棋盤大小</div><button class="size-btn active" data-size="small">小</button><button class="size-btn" data-size="medium">中</button><button class="size-btn" data-size="large">大</button></div><button class="new-game-btn">🔄 新游戲</button></div><div class="status-bar"><div class="status-item">?? 時間: <span id="timer">0</span>秒</div><div class="status-item">💣 剩余: <span id="mine-count">10</span></div><div class="status-item">🚩 標記: <span id="flag-count">0</span></div></div><div class="grid-container"><div id="grid" class="grid"></div></div><div id="status" class="status-message">歡迎來到掃雷游戲!選擇難度后開始游戲</div><div class="instructions"><h3>游戲說明:</h3><p>? 左鍵點擊:揭開格子</p><p>? 右鍵點擊:標記/取消標記地雷</p><p>? 勝利條件:標記所有地雷并揭開所有安全格子</p><p>? 失敗條件:點擊到地雷格子</p></div></div><script>// 游戲配置const DIFFICULTY = {beginner: { rows: 9, cols: 9, mines: 10 },intermediate: { rows: 16, cols: 16, mines: 40 },expert: { rows: 16, cols: 30, mines: 99 }};// 修復:正確定義 SIZE_FACTOR 常量const SIZE_FACTOR = {small: 0.8,medium: 1.0,large: 1.2};// 游戲狀態let gameConfig = { ...DIFFICULTY.beginner, sizeFactor: SIZE_FACTOR.small };let board = [];let revealed = [];let flagged = [];let mines = [];let gameOver = false;let gameWon = false;let firstClick = true;let timer = 0;let timerInterval = null;let remainingMines = gameConfig.mines;let flagCount = 0;// DOM元素const gridElement = document.getElementById('grid');const statusElement = document.getElementById('status');const timerElement = document.getElementById('timer');const mineCountElement = document.getElementById('mine-count');const flagCountElement = document.getElementById('flag-count');const newGameBtn = document.querySelector('.new-game-btn');// 初始化游戲function initGame() {// 重置游戲狀態clearInterval(timerInterval);timer = 0;timerElement.textContent = timer;gameOver = false;gameWon = false;firstClick = true;remainingMines = gameConfig.mines;flagCount = 0;mineCountElement.textContent = remainingMines;flagCountElement.textContent = flagCount;statusElement.textContent = "游戲開始!點擊任意格子";statusElement.className = "status-message";// 初始化數組board = [];revealed = [];flagged = [];mines = [];// 創建棋盤createBoard();renderBoard();}// 創建棋盤數據結構function createBoard() {// 初始化二維數組for (let i = 0; i < gameConfig.rows; i++) {board[i] = [];revealed[i] = [];flagged[i] = [];for (let j = 0; j < gameConfig.cols; j++) {board[i][j] = 0;revealed[i][j] = false;flagged[i][j] = false;}}}// 渲染棋盤到DOMfunction renderBoard() {gridElement.innerHTML = '';gridElement.style.gridTemplateColumns = `repeat(${gameConfig.cols}, 1fr)`;// 應用尺寸因子const cellSize = Math.floor(30 * gameConfig.sizeFactor);document.documentElement.style.setProperty('--cell-size', `${cellSize}px`);for (let i = 0; i < gameConfig.rows; i++) {for (let j = 0; j < gameConfig.cols; j++) {const cell = document.createElement('div');cell.className = 'cell';cell.dataset.row = i;cell.dataset.col = j;// 添加點擊事件cell.addEventListener('click', () => handleCellClick(i, j));cell.addEventListener('contextmenu', (e) => {e.preventDefault();handleRightClick(i, j);});gridElement.appendChild(cell);}}}// 放置地雷(確保第一次點擊安全)function placeMines(firstRow, firstCol) {mines = [];let minesPlaced = 0;// 確保第一次點擊周圍沒有地雷const safeCells = [];for (let i = -1; i <= 1; i++) {for (let j = -1; j <= 1; j++) {const newRow = firstRow + i;const newCol = firstCol + j;if (newRow >= 0 && newRow < gameConfig.rows && newCol >= 0 && newCol < gameConfig.cols) {safeCells.push(`${newRow},${newCol}`);}}}// 隨機放置地雷while (minesPlaced < gameConfig.mines) {const row = Math.floor(Math.random() * gameConfig.rows);const col = Math.floor(Math.random() * gameConfig.cols);// 跳過第一次點擊及其周圍的格子if (row === firstRow && col === firstCol) continue;if (safeCells.includes(`${row},${col}`)) continue;if (board[row][col] === -1) continue;board[row][col] = -1;mines.push({ row, col });minesPlaced++;// 更新周圍格子的數字for (let i = -1; i <= 1; i++) {for (let j = -1; j <= 1; j++) {const newRow = row + i;const newCol = col + j;if (newRow >= 0 && newRow < gameConfig.rows && newCol >= 0 && newCol < gameConfig.cols && board[newRow][newCol] !== -1) {board[newRow][newCol]++;}}}}}// 處理格子點擊function handleCellClick(row, col) {if (gameOver || gameWon || flagged[row][col]) return;// 如果是第一次點擊,放置地雷if (firstClick) {placeMines(row, col);firstClick = false;// 開始計時timerInterval = setInterval(() => {timer++;timerElement.textContent = timer;}, 1000);}// 如果點擊到地雷if (board[row][col] === -1) {revealMines();gameOver = true;statusElement.textContent = "游戲結束!你踩到地雷了 💥";statusElement.classList.add("game-over");clearInterval(timerInterval);return;}// 揭示格子revealCell(row, col);// 檢查勝利條件checkWin();}// 處理右鍵點擊(標記旗幟)function handleRightClick(row, col) {if (gameOver || gameWon || revealed[row][col]) return;// 切換旗幟狀態flagged[row][col] = !flagged[row][col];flagCount += flagged[row][col] ? 1 : -1;flagCountElement.textContent = flagCount;// 更新UIconst cell = document.querySelector(`.cell[data-row="${row}"][data-col="${col}"]`);if (flagged[row][col]) {cell.classList.add('flagged');cell.textContent = '🚩';} else {cell.classList.remove('flagged');cell.textContent = '';}// 更新剩余地雷計數remainingMines = gameConfig.mines - flagCount;mineCountElement.textContent = remainingMines;// 檢查勝利條件checkWin();}// 揭示格子function revealCell(row, col) {if (revealed[row][col] || flagged[row][col]) return;revealed[row][col] = true;const cell = document.querySelector(`.cell[data-row="${row}"][data-col="${col}"]`);cell.classList.add('revealed');if (board[row][col] > 0) {cell.textContent = board[row][col];cell.classList.add(`num-${board[row][col]}`);} else if (board[row][col] === 0) {// 如果是空白格子,遞歸揭示周圍格子for (let i = -1; i <= 1; i++) {for (let j = -1; j <= 1; j++) {const newRow = row + i;const newCol = col + j;if (newRow >= 0 && newRow < gameConfig.rows && newCol >= 0 && newCol < gameConfig.cols) {revealCell(newRow, newCol);}}}}}// 揭示所有地雷(游戲結束時)function revealMines() {mines.forEach(mine => {const cell = document.querySelector(`.cell[data-row="${mine.row}"][data-col="${mine.col}"]`);if (!flagged[mine.row][mine.col]) {cell.classList.add('mine', 'revealed');cell.textContent = '💣';}});}// 檢查勝利條件function checkWin() {// 檢查是否所有非地雷格子都被揭示let allRevealed = true;for (let i = 0; i < gameConfig.rows; i++) {for (let j = 0; j < gameConfig.cols; j++) {if (board[i][j] !== -1 && !revealed[i][j]) {allRevealed = false;break;}}if (!allRevealed) break;}// 檢查是否所有地雷都被正確標記let allMinesFlagged = true;mines.forEach(mine => {if (!flagged[mine.row][mine.col]) {allMinesFlagged = false;}});if (allRevealed || allMinesFlagged) {gameWon = true;clearInterval(timerInterval);statusElement.textContent = `恭喜獲勝!用時 ${timer} 秒 🎉`;statusElement.classList.add("win");revealMines();}}// 設置難度function setDifficulty(difficulty) {gameConfig = { ...DIFFICULTY[difficulty], sizeFactor: gameConfig.sizeFactor };// 更新UIdocument.querySelectorAll('.difficulty-btn').forEach(btn => {btn.classList.toggle('active', btn.dataset.difficulty === difficulty);});initGame();}// 設置棋盤大小(確保調用initGame重新初始化)function setSize(size) {gameConfig.sizeFactor = SIZE_FACTOR[size];// 更新UIdocument.querySelectorAll('.size-btn').forEach(btn => {btn.classList.toggle('active', btn.dataset.size === size);});// 重新初始化游戲以應用新尺寸initGame();}// 事件監聽document.querySelectorAll('.difficulty-btn').forEach(btn => {btn.addEventListener('click', () => setDifficulty(btn.dataset.difficulty));});document.querySelectorAll('.size-btn').forEach(btn => {btn.addEventListener('click', () => setSize(btn.dataset.size));});newGameBtn.addEventListener('click', initGame);// 初始化游戲initGame();</script>
</body>
</html>