第一版扫雷小游戏有个朋友评论说没有标记为雷的功能,然后-->

先展示一下扫雷在Excel中的样子。玩之前记得调成正方形比较好…

现在,右键点击任何未揭开的格子均会切换标记状态(显示黄色“P”),而不会误触雷区。再次右键点击已标记格子可取消标记。
(老话重谈)接下来开始讲解如何制作属于自己的Excel扫雷小游戏:
首先第一步需要新建一个Excel表
,不需要修改名字,因为复制代码后需要改名并且另存为xlsm格式才可以运行。
然后第二步需要插入新模块并且复制代码进去,不会插入新模块的详见教学【边学边分享】001 VBA长什么样?代码如下:
Option ExplicitPublic Const GRID_SIZE As Integer = 20Public Const MINE_COUNT As Integer = 50Public Mines() As BooleanPublic Revealed() As BooleanPublic Marked() As BooleanPublic GameOver As BooleanPublic FirstClick As BooleanSub InitializeGame(Optional safeRow As Integer = 0, Optional safeCol As Integer = 0)Dim i As Integer, j As Integer, count As IntegerGameOver = FalseFirstClick = False' 验证安全坐标有效性If safeRow < 1 Or safeRow > GRID_SIZE Then safeRow = 0If safeCol < 1 Or safeCol > GRID_SIZE Then safeCol = 0' 初始化数组ReDim Mines(1 To GRID_SIZE, 1 To GRID_SIZE)ReDim Revealed(1 To GRID_SIZE, 1 To GRID_SIZE)ReDim Marked(1 To GRID_SIZE, 1 To GRID_SIZE)' 清空游戏区域With Sheet1.Range("A1:T20").Clear.Range("A1:T20").Interior.Color = RGB(192, 192, 192).Range("A1:T20").Font.Color = RGB(0, 0, 0).Range("A1:T20").Borders.LineStyle = xlContinuousEnd With' 随机生成地雷(避开安全坐标)RandomizeDo While count < MINE_COUNTi = Int(GRID_SIZE * Rnd) + 1j = Int(GRID_SIZE * Rnd) + 1' 确保坐标有效且不在安全位置If i >= 1 And i <= GRID_SIZE And _j >= 1 And j <= GRID_SIZE And _Not (i = safeRow And j = safeCol) ThenIf Not Mines(i, j) ThenMines(i, j) = Truecount = count + 1End IfEnd IfLoopEnd SubSub RevealCell(row As Integer, col As Integer)If row < 1 Or row > GRID_SIZE Or col < 1 Or col > GRID_SIZE Then Exit SubIf Revealed(row, col) Or Marked(row, col) Then Exit SubRevealed(row, col) = TrueDim count As Integer: count = CountAdjacentMines(row, col)With Sheet1.Cells(row, col).Interior.Color = RGB(255, 255, 255)If count > 0 Then.Value = countSelect Case countCase 1: .Font.Color = RGB(0, 0, 255)Case 2: .Font.Color = RGB(0, 128, 0)Case 3: .Font.Color = RGB(255, 0, 0)Case 4: .Font.Color = RGB(0, 0, 128)Case Else: .Font.Color = RGB(128, 0, 128)End SelectElse' 递归揭开周围单元格Dim i As Integer, j As IntegerFor i = row - 1 To row + 1For j = col - 1 To col + 1If i <> row Or j <> col ThenRevealCell i, jEnd IfNext jNext iEnd IfEnd WithEnd SubFunction CountAdjacentMines(row As Integer, col As Integer) As IntegerDim i As Integer, j As Integer, count As IntegerFor i = row - 1 To row + 1For j = col - 1 To col + 1If i >= 1 And i <= GRID_SIZE And j >= 1 And j <= GRID_SIZE ThenIf Mines(i, j) Then count = count + 1End IfNext jNext iCountAdjacentMines = countEnd FunctionSub GameLost()GameOver = TrueDim i As Integer, j As IntegerFor i = 1 To GRID_SIZEFor j = 1 To GRID_SIZEIf Mines(i, j) ThenSheet1.Cells(i, j).Interior.Color = RGB(255, 0, 0)Sheet1.Cells(i, j).Value = " X"End IfNext jNext iMsgBox "游戏结束!你输了!", vbCriticalInitializeGameEnd SubFunction CheckWin() As BooleanDim i As Integer, j As IntegerFor i = 1 To GRID_SIZEFor j = 1 To GRID_SIZEIf Not Mines(i, j) And Not Revealed(i, j) Then Exit FunctionNext jNext iCheckWin = TrueMsgBox "恭喜!你赢了!", vbInformationInitializeGameEnd FunctionSub RestartGame()InitializeGameEnd Sub
打开Sheet1,复制如下代码:
Option Explicit' API 函数声明:检测鼠标右键是否被按下(兼容 32/64 位 Excel)' 如果编译出错,请尝试删除 "PtrSafe" 关键字Private Declare PtrSafe Function GetAsyncKeyState Lib "user32" (ByVal vKey As Long) As IntegerPrivate Sub Worksheet_SelectionChange(ByVal Target As Range)' 检测右键是否被按下,如果是则忽略此次选中变化(由右键引起)If GetAsyncKeyState(vbKeyRButton) And &H8000 ThenExit SubEnd IfIf GameOver Then Exit SubIf Intersect(Target, Me.Range("A1:T20")) Is Nothing Then Exit SubApplication.EnableEvents = FalseDim row As Integer: row = Target.rowDim col As Integer: col = Target.Column' 加强边界检查If row < 1 Or row > GRID_SIZE Or col < 1 Or col > GRID_SIZE ThenApplication.EnableEvents = TrueExit SubEnd If' 首次点击保护If Not FirstClick Then' 确保Mines数组已初始化If Not IsArrayInitialized(Mines) ThenInitializeGameEnd If' 如果首次点击是地雷,重新生成布局If Mines(row, col) ThenInitializeGame row, colEnd IfFirstClick = TrueEnd IfIf Not Revealed(row, col) And Not Marked(row, col) ThenIf Mines(row, col) ThenGameLostElseRevealCell row, colCheckWinEnd IfEnd If' 安全取消选中On Error Resume NextMe.Range("A11").SelectApplication.EnableEvents = TrueEnd Sub' ========== 鼠标右键标记地雷 ==========Private Sub Worksheet_BeforeRightClick(ByVal Target As Range, Cancel As Boolean)' 阻止默认右键菜单弹出Cancel = True' 仅当游戏已开始且未结束时,才执行标记/取消标记If FirstClick And Not GameOver Then' 仅处理游戏区域内的单元格If Intersect(Target, Me.Range("A1:T20")) Is Nothing Then Exit SubDim row As Integer: row = Target.RowDim col As Integer: col = Target.Column' 边界检查If row < 1 Or row > GRID_SIZE Or col < 1 Or col > GRID_SIZE Then Exit Sub' 已揭开的格子不能标记If Revealed(row, col) Then Exit Sub' 切换标记状态(禁止事件触发,避免循环)Application.EnableEvents = FalseIf Marked(row, col) Then' 取消标记:恢复灰色背景,清空内容Marked(row, col) = FalseWith Me.Cells(row, col).ClearContents.Interior.Color = RGB(192, 192, 192)End WithElse' 添加标记:显示“P”并设为黄色背景Marked(row, col) = TrueWith Me.Cells(row, col).Value = "P" ' 可替换为旗帜符号如 "⚑".Interior.Color = RGB(255, 255, 0) ' 黄色背景.Font.Color = RGB(0, 0, 0)End WithEnd IfApplication.EnableEvents = TrueEnd IfEnd Sub' ========== 右键标记结束 ==========' 辅助函数:检查数组初始化状态Private Function IsArrayInitialized(arr As Variant) As BooleanOn Error Resume NextIsArrayInitialized = IsArray(arr) And _Not IsError(LBound(arr, 1)) And _UBound(arr, 1) >= LBound(arr, 1)End Function
为了方便重置游戏,还需要在开发工具下插入表单控件中的按钮控件,选择RestartGame宏即可。
注意事项:
需要启用宏才能运行
游戏区域为A1-T20(20x20网格)
包含50个随机生成的地雷
最后的最后,如果有不会玩扫雷游戏的请看下扫雷规则:
你点到一个数字,如果是3,那就说明最靠近他它周围的8个格里有3个雷, 然后通过相邻或者相间的数字之间的交集来判断哪些是雷。
赢了如下图:(为了这个截图我玩了十几把
)

输了如下图:
