扫雷游戏开发教程:从零打造精美像素扫雷

完整源码在本文结尾处

在这里插入图片描述

一、游戏概述

扫雷是一款经典的益智游戏,玩家需要在不触发地雷的情况下揭开所有安全格子。本教程将带你从零开始开发一个具有精美界面和动画效果的扫雷游戏,包含难度选择、棋盘大小调整等高级功能。

二、游戏核心功能

  1. 三种难度级别:初级(9×9)、中级(16×16)、高级(16×30)
  2. 棋盘大小调整:小、中、大三种尺寸
  3. 计时系统:记录游戏用时
  4. 地雷计数器:显示剩余地雷数量
  5. 标记系统:右键标记可疑地雷位置
  6. 动画效果:格子揭示、地雷爆炸、胜利庆祝等动画

三、开发步骤详解

  1. 游戏数据结构设计
// 游戏配置
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 = [];          // 存储所有地雷位置
  1. 初始化游戏
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;}}
}
  1. 渲染棋盘
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);}}
}
  1. 放置地雷(确保第一次点击安全)
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]++;}}}}
}
  1. 处理格子点击
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);}}}}
}
  1. 右键标记功能
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();
}
  1. 胜利条件检查
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样式解析

  1. 格子基础样式
.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);
}
  1. 动画效果
/* 揭示动画 */
.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); }
}

五、如何扩展游戏

  1. 添加关卡系统:设计不同主题的关卡(沙漠、雪地、太空等)
  2. 实现存档功能:使用localStorage保存游戏进度
  3. 添加音效:为点击、爆炸、胜利等事件添加音效
  4. 设计成就系统:根据游戏表现解锁成就
  5. 添加多人模式:实现玩家间的竞争或合作模式

六、开发小贴士

  1. 测试驱动开发:先编写测试用例再实现功能
  2. 模块化设计:将游戏拆分为独立模块(渲染、逻辑、事件处理)
  3. 性能优化:对于大型棋盘使用虚拟滚动技术
  4. 响应式设计:确保在不同设备上都有良好的体验
  5. 代码注释:为复杂逻辑添加详细注释

七、总结

通过本教程,你已经学会了如何开发一个功能完整的扫雷游戏。记住,游戏开发就像扫雷一样——需要耐心、策略和一点冒险精神!当你遇到"地雷"(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>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/90824.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/90824.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux驱动开发笔记(五)——设备树(上)

内容详见《【正点原子】I.MX6U嵌入式Linux驱动开发指南》四十三章 开发板&#xff1a;imx6ull mini 虚拟机&#xff1a;VMware17 ubuntu&#xff1a;ubuntu20.04 一、什么是设备树 视频&#xff1a;第6.1讲 Linux设备树详解-什么是设备树&#xff1f;_哔哩哔哩_bilibili 对…

【QT入门到晋级】window opencv安装及引入qtcreator(包含两种qt编译器:MSVC和MinGW)

前言 本文主要分享QT的两种编译器环境&#xff08;MSVC和MinGW&#xff09;下&#xff0c;安装及引入opencv的方法。 编译器区别 特性​​​​MSVC​​​​MinGW​​​​编译器类型​​微软专有编译器&#xff08;cl.exe&#xff09;基于GCC的开源工具链​​平台支持​​仅Wi…

字节跳动Coze Studio开源了!架构解析

Coze Studio 是字节跳动推出的一款 AI 应用开发平台&#xff0c;专注于帮助开发者快速构建、测试和部署基于大语言模型的智能应用。其整体架构围绕“低代码开发 AI 应用”的核心目标设计&#xff0c;融合了模型能力、工具集成、流程编排和多端部署等功能。以下是其整体架构的详…

Claude 4.0 终极编程指南:模型对比、API配置与IDE集成实战

Claude 4.0 终极编程指南&#xff1a;模型对比、API配置与IDE集成实战 基于官方文档及可验证数据源&#xff08;2025年7月更新&#xff09; 1 Claude 4.0 技术解析&#xff1a;对比竞品的核心优势与局限 1.1 官方性能数据&#xff08;来源&#xff1a;Anthropic技术白皮书&…

优化:Toc小程序猜你喜欢功能

引言&#xff1a;来自自创的小程序中热点接口&#xff0c;本小程序专为在校学生自提点餐使用 一、功能描述 该功能作为一个推荐的职责&#xff0c;根据用户最近行为给用户推荐用户可能喜欢去吃的店铺&#xff0c;可能比较简洁&#xff0c;但是需要设计的方面挺多的&#xff0c…

Datawhale AI 夏令营:让AI理解列车排期表 Notebook(Baseline拆解)

Step1、读取数据 import pandas as pd import requests import re import json from tqdm import tqdm# 读取数据 data pd.read_excel(data/info_table.xlsx) data data.fillna(无数据) dataStep2、注册硅基流动https://cloud.siliconflow.cnQwen/Qwen3-8B 模型可以免费使用&…

vue写的app设置角标

原生App角标&#xff08;UniApp示例&#xff09;调用plus.runtime.setBadgeNumber方法设置安卓/iOS角标&#xff1a;javascriptCopy Code// 设置角标 plus.runtime.setBadgeNumber(99); // 清除角标&#xff08;部分平台需特殊处理&#xff09; plus.runtime.setBadgeNumber(0)…

GAN/cGAN中到底要不要注入噪声

MelGAN论文MelGAN针对的是从mel谱生成语音&#xff0c;里面说当条件很强的时候&#xff0c;随机噪声就没啥用了&#xff0c;因此没将noise注入到生成器中&#xff1b;运用的判别器也仅有1个输入&#xff0c;不是cGAN的形式image-to-image translation with conditional adversa…

备份一下我的 mac mini 的环境变量配置情况

export PATH“/opt/homebrew/bin:$PATH” #THIS MUST BE AT THE END OF THE FILE FOR SDKMAN TO WORK!!! export SDKMAN_DIR“HOME/.sdkman"[[−s"HOME/.sdkman" [[ -s "HOME/.sdkman"[[−s"HOME/.sdkman/bin/sdkman-init.sh” ]] && so…

JVM学习日记(十)Day10

G1回收器 这一篇是详细说明G1回收器的&#xff0c;因为他相对来说确实是个缝合怪&#xff0c;上篇的内容又太多了所不清楚&#xff0c;所有这一篇进行详细的说明&#xff0c; 第一个呢就是其实G1是兼顾并行和并发的&#xff0c;简单来说就是既可以并行也可以并发&#xff0c;…

使用IP扫描工具排查网络问题

随着企业的发展&#xff0c;网络中会新增各类设备&#xff0c;从台式机、服务器到物联网设备和虚拟机&#xff08;VMs&#xff09;&#xff0c;所有这些设备都通过复杂的子网和虚拟局域网&#xff08;VLAN&#xff09;相连。 这种复杂性给 IT 团队带来了压力&#xff0c;他们需…

Wireshark TS | 发送数据超出接收窗口

前言 来自于测试中无意发现到的一个接收窗口满的案例&#xff0c;特殊&#xff0c;或者可以说我以前都没在实际场景中见过。一开始都没整太明白&#xff0c;花了些精力才算是弄清楚了些&#xff0c;记录分享下。 问题说明 在研究拥塞控制的慢启动阶段时&#xff0c;通过 packet…

C语言自定义数据类型详解(四)——联合体

好的&#xff0c;接下来我们来学习最后一个自定义数据类型——联合体。 一、什么是联合体&#xff1a; 联合体又叫共用体&#xff0c;用关键字union来进行定义。又因为所有的成员变量共用同一段内存空间&#xff08;关于这一点&#xff0c;我们不久就会加以验证&#xff09;&…

[python][flask]Flask-Login 使用详解

1. 简介Flask-Login 是 Flask 的一个扩展&#xff0c;专门用于处理用户认证相关的功能。它提供了用户会话管理、登录/注销视图、记住我功能等常见认证需求&#xff0c;让开发者能够快速实现安全的用户认证系统。2. 安装与基础配置首先&#xff0c;需要安装 Flask-Login&#xf…

【WebGPU学习杂记】WebAssembly中的relaxed_madd指令到底做了什么?

relaxed_madd 这条指令到底做了什么核心&#xff1a;relaxed_madd 是一个分量级别 (Component-wise) 的操作 首先&#xff0c;最重要的一点是&#xff1a;v128.relaxed_madd<f32>(a, b, c) 不是矩阵乘法。它是一个在三个向量 a, b, c 之间进行的、逐个分量的、并行的融合…

【全新上线】境内 Docker 镜像状态监控

境内 Docker 镜像状态监控&#xff1a;您的 Docker 加速伴侣 在当今云计算和容器化技术飞速发展的时代&#xff0c;Docker 已成为开发者不可或缺的工具。然而&#xff0c;对于身处国内的用户而言&#xff0c;访问境外 Docker Hub 等镜像仓库时常会遭遇网络延迟和连接不稳定的困…

Visual Studio中部署PaddleOCRv5 (借助ncnn框架)

PaddleOCRv5_ncnn PaddleOCRv5 在Visual Studio中进行图片OCR检测&#xff08;ncnn框架open-mobile实现)&#xff0c;尝试对nihui的ncnn-android-ppocrv5检测算法的剥离与移植。 本项目Github链接如下&#xff1a;PaddleOCRv5_ncnn 写在前面 本仓库代码是基于nihui的ncnn-a…

中级全栈工程师笔试题

解释ACID特性&#xff0c;如何在node.js中实现事务操作针对React单页应用&#xff0c;请提供至少5种性能优化方案&#xff0c;并解释其原理&#xff1a; 减少首屏加载时间优化渲染性能资源加载策略状态管理优化代码分割方案 如何防止以下攻击&#xff1a; JWT令牌挟持Graph QL查…

Windows---动态链接库Dynamic Link Library(.dll)

DLL的“幕后英雄”角色 在Windows操作系统的生态中&#xff0c;有一类文件始终扮演着“幕后英雄”的角色——它们不像.exe文件那样直接呈现为用户可见的程序窗口&#xff0c;却支撑着几乎所有应用程序的运行&#xff1b;它们不单独执行&#xff0c;却承载着系统与软件的核心功…

深入分析计算机网络传输层和应用层面试题

三、传输层面试题&#xff08;Transmission Layer&#xff09;传输层位于 OSI 七层模型的第四层&#xff0c;它的核心任务是为两个主机之间的应用层提供可靠的数据传输服务。它不仅承担了数据的端到端传输&#xff0c;而且还实现了诸如差错检测、数据流控制、拥塞控制等机制&am…