相关文件
关注小编,私信小编可以领取源码哟,还有其他的游戏源码的哟~~
当然别忘了一键三连哈~

开发工具

Python版本:3.6.4
相关模块:
pygame模块;
以及一些python自带的模块。

环境搭建
安装Python并添加到环境变量,pip安装需要的相关模块即可。

原理介绍
因为时间有点赶,所以这里我只简单介绍一下游戏的实现思路。
相信大家对扫雷这款windows自带的经典小游戏都不陌生,它的游戏规则很简单:

游戏界面左上角的数字代表所有方格中埋有雷的数目,右上角是一个计时器。你要做的就是根据提示找出方格中所有的雷。
那么提示是啥呢?很简单,游戏刚开始的时候你需要随便点一个方格,就像这样:

上面的数字代表以该数字为中心的九宫格内埋有的雷的数目。所以如果你人品不好,一开始就点到雷的话,这局游戏就直接GG了。
ok,了解了游戏规则之后,我们就可以开始写代码了。首先还是先初始化一下游戏:

# 游戏初始化
pygame.init()
screen = pygame.display.set_mode(cfg.SCREENSIZE)
pygame.display.set_caption('扫雷 ———— 彳余大胆')

然后把需要用到的字体,图片,音乐啥的都导入进来:

# 导入所有图片
images = {}
for key, value in cfg.IMAGE_PATHS.items():if key in ['face_fail', 'face_normal', 'face_success']:image = pygame.image.load(value)images[key] = pygame.transform.smoothscale(image, (int(cfg.GRIDSIZE*1.25), int(cfg.GRIDSIZE*1.25)))else:image = pygame.image.load(value).convert()images[key] = pygame.transform.smoothscale(image, (cfg.GRIDSIZE, cfg.GRIDSIZE))
# 载入字体
font = pygame.font.Font(cfg.FONT_PATH, cfg.FONT_SIZE)
# 导入并播放背景音乐
pygame.mixer.music.load(cfg.BGM_PATH)
pygame.mixer.music.play(-1)

接着,我们来定义一个文字板,用于显示左上角的埋雷数量和右上角的游戏已进行时间:

'''文字板'''
class TextBoard(pygame.sprite.Sprite):def __init__(self, text, font, position, color, **kwargs):pygame.sprite.Sprite.__init__(self)self.text = textself.font = fontself.position = positionself.color = colordef draw(self, screen):text_render = self.font.render(self.text, True, self.color)screen.blit(text_render, self.position)def update(self, text):self.text = text

其实很简单,只需要把用字体渲染之后的文本对象绑定到屏幕上就行,然后设置一个update函数,来实时更新里面的文本内容。

然后,我们再定义一个表情按钮类:

'''表情按钮'''
class EmojiButton(pygame.sprite.Sprite):def __init__(self, images, position, status_code=0, **kwargs):pygame.sprite.Sprite.__init__(self)# 导入图片self.images = imagesself.image = self.images['face_normal']self.rect = self.image.get_rect()self.rect.left, self.rect.top = position# 表情按钮的当前状态self.status_code = status_code'''画到屏幕上'''def draw(self, screen):# 状态码为0, 代表正常的表情if self.status_code == 0:self.image = self.images['face_normal']# 状态码为1, 代表失败的表情elif self.status_code == 1:self.image = self.images['face_fail']# 状态码为2, 代表成功的表情elif self.status_code == 2:self.image = self.images['face_success']# 绑定图片到屏幕screen.blit(self.image, self.rect)'''设置当前的按钮的状态'''def setstatus(self, status_code):self.status_code = status_code

当鼠标点击到这个按钮的时,就重新开始新的游戏(无论当前的游戏状态如何,都将重新开始新的游戏):

接下来,我们需要定义的就是下面的方格类了:

'''雷'''
class Mine(pygame.sprite.Sprite):def __init__(self, images, position, status_code=0, **kwargs):pygame.sprite.Sprite.__init__(self)# 导入图片self.images = imagesself.image = self.images['blank']self.rect = self.image.get_rect()self.rect.left, self.rect.top = position# 雷当前的状态self.status_code = status_code# 真雷还是假雷(默认是假雷)self.is_mine_flag = False# 周围雷的数目self.num_mines_around = -1'''设置当前的状态码'''def setstatus(self, status_code):self.status_code = status_code'''埋雷'''def burymine(self):self.is_mine_flag = True'''设置周围雷的数目'''def setnumminesaround(self, num_mines_around):self.num_mines_around = num_mines_around'''画到屏幕上'''def draw(self, screen):# 状态码为0, 代表该雷未被点击if self.status_code == 0:self.image = self.images['blank']# 状态码为1, 代表该雷已被点开elif self.status_code == 1:self.image = self.images['mine'] if self.is_mine_flag else self.images[str(self.num_mines_around)]# 状态码为2, 代表该雷被玩家标记为雷elif self.status_code == 2:self.image = self.images['flag']# 状态码为3, 代表该雷被玩家标记为问号elif self.status_code == 3:self.image = self.images['ask']# 状态码为4, 代表该雷正在被鼠标左右键双击elif self.status_code == 4:assert not self.is_mine_flagself.image = self.images[str(self.num_mines_around)]# 状态码为5, 代表该雷在被鼠标左右键双击的雷的周围elif self.status_code == 5:self.image = self.images['0']# 状态码为6, 代表该雷被踩中elif self.status_code == 6:assert self.is_mine_flagself.image = self.images['blood']# 状态码为7, 代表该雷被误标elif self.status_code == 7:assert not self.is_mine_flagself.image = self.images['error']# 绑定图片到屏幕screen.blit(self.image, self.rect)@propertydef opened(self):return self.status_code == 1

它的主要作用就是记录游戏地图中某个方格的状态(比如是不是埋了雷呀,有没有被点开呀,有没有被标记呀之类的)。
最后定义一个游戏地图类,来把游戏地图中的所有方格都整合在一起方便在游戏主循环里调用更新:

'''扫雷地图'''
class MinesweeperMap():def __init__(self, cfg, images, **kwargs):self.cfg = cfg# 雷型矩阵self.mines_matrix = []for j in range(cfg.GAME_MATRIX_SIZE[1]):mines_line = []for i in range(cfg.GAME_MATRIX_SIZE[0]):position = i * cfg.GRIDSIZE + cfg.BORDERSIZE, (j + 2) * cfg.GRIDSIZEmines_line.append(Mine(images=images, position=position))self.mines_matrix.append(mines_line)# 随机埋雷for i in random.sample(range(cfg.GAME_MATRIX_SIZE[0]*cfg.GAME_MATRIX_SIZE[1]), cfg.NUM_MINES):self.mines_matrix[i//cfg.GAME_MATRIX_SIZE[0]][i%cfg.GAME_MATRIX_SIZE[0]].burymine()count = 0for item in self.mines_matrix:for i in item:count += int(i.is_mine_flag)# 游戏当前的状态self.status_code = -1# 记录鼠标按下时的位置和按的键self.mouse_pos = Noneself.mouse_pressed = None'''画出当前的游戏状态图'''def draw(self, screen):for row in self.mines_matrix:for item in row: item.draw(screen)'''设置当前的游戏状态'''def setstatus(self, status_code):# 0: 正在进行游戏, 1: 游戏结束, -1: 游戏还没开始self.status_code = status_code'''根据玩家的鼠标操作情况更新当前的游戏状态地图'''def update(self, mouse_pressed=None, mouse_pos=None, type_='down'):assert type_ in ['down', 'up']# 记录鼠标按下时的位置和按的键if type_ == 'down' and mouse_pos is not None and mouse_pressed is not None:self.mouse_pos = mouse_posself.mouse_pressed = mouse_pressed# 鼠标点击的范围不在游戏地图内, 无响应if self.mouse_pos[0] < self.cfg.BORDERSIZE or self.mouse_pos[0] > self.cfg.SCREENSIZE[0] - self.cfg.BORDERSIZE or \self.mouse_pos[1] < self.cfg.GRIDSIZE * 2 or self.mouse_pos[1] > self.cfg.SCREENSIZE[1] - self.cfg.BORDERSIZE:return# 鼠标点击在游戏地图内, 代表开始游戏(即可以开始计时了)if self.status_code == -1:self.status_code = 0# 如果不是正在游戏中, 按鼠标是没有用的if self.status_code != 0:return# 鼠标位置转矩阵索引coord_x = (self.mouse_pos[0] - self.cfg.BORDERSIZE) // self.cfg.GRIDSIZEcoord_y = self.mouse_pos[1] // self.cfg.GRIDSIZE - 2mine_clicked = self.mines_matrix[coord_y][coord_x]# 鼠标按下if type_ == 'down':# --鼠标左右键同时按下if self.mouse_pressed[0] and self.mouse_pressed[2]:if mine_clicked.opened and mine_clicked.num_mines_around > 0:mine_clicked.setstatus(status_code=4)num_flags = 0coords_around = self.getaround(coord_y, coord_x)for (j, i) in coords_around:if self.mines_matrix[j][i].status_code == 2:num_flags += 1if num_flags == mine_clicked.num_mines_around:for (j, i) in coords_around:if self.mines_matrix[j][i].status_code == 0:self.openmine(i, j)else:for (j, i) in coords_around:if self.mines_matrix[j][i].status_code == 0:self.mines_matrix[j][i].setstatus(status_code=5)# 鼠标释放else:# --鼠标左键if self.mouse_pressed[0] and not self.mouse_pressed[2]:if not (mine_clicked.status_code == 2 or mine_clicked.status_code == 3):if self.openmine(coord_x, coord_y):self.setstatus(status_code=1)# --鼠标右键elif self.mouse_pressed[2] and not self.mouse_pressed[0]:if mine_clicked.status_code == 0:mine_clicked.setstatus(status_code=2)elif mine_clicked.status_code == 2:mine_clicked.setstatus(status_code=3)elif mine_clicked.status_code == 3:mine_clicked.setstatus(status_code=0)# --鼠标左右键同时按下elif self.mouse_pressed[0] and self.mouse_pressed[2]:mine_clicked.setstatus(status_code=1)coords_around = self.getaround(coord_y, coord_x)for (j, i) in coords_around:if self.mines_matrix[j][i].status_code == 5:self.mines_matrix[j][i].setstatus(status_code=0)'''打开雷'''def openmine(self, x, y):mine_clicked = self.mines_matrix[y][x]if mine_clicked.is_mine_flag:for row in self.mines_matrix:for item in row:if not item.is_mine_flag and item.status_code == 2:item.setstatus(status_code=7)elif item.is_mine_flag and item.status_code == 0:item.setstatus(status_code=1)mine_clicked.setstatus(status_code=6)return Truemine_clicked.setstatus(status_code=1)coords_around = self.getaround(y, x)num_mines = 0for (j, i) in coords_around:num_mines += int(self.mines_matrix[j][i].is_mine_flag)mine_clicked.setnumminesaround(num_mines)if num_mines == 0:for (j, i) in coords_around:if self.mines_matrix[j][i].num_mines_around == -1:self.openmine(i, j)return False'''获得坐标点的周围坐标点'''def getaround(self, row, col):coords = []for j in range(max(0, row-1), min(row+1, self.cfg.GAME_MATRIX_SIZE[1]-1)+1):for i in range(max(0, col-1), min(col+1, self.cfg.GAME_MATRIX_SIZE[0]-1)+1):if j == row and i == col:continuecoords.append((j, i))return coords'''是否正在游戏中'''@propertydef gaming(self):return self.status_code == 0'''被标记为雷的雷数目'''@propertydef flags(self):num_flags = 0for row in self.mines_matrix:for item in row: num_flags += int(item.status_code == 2)return num_flags'''已经打开的雷的数目'''@propertydef openeds(self):num_openeds = 0for row in self.mines_matrix:for item in row: num_openeds += int(item.opened)return num_openeds

这里只解释几个可能有小伙伴看不太懂的地方:

  • 打开雷的时候我们用了递归,作用是当点击到的方格周围都没有雷的时候,系统就自动打开这个方格周围的方格,以实现有时候点击一个方格可以打开一大片方格的效果,这里的周围都特指以目标方格为中心的九宫格内的所有方格;
  • 鼠标左右键一起按在已经打开的方格上的话,如果这个方格周围的方格已经被标记为雷的数目和这个方格上显示的数字一致,就把这个方格周围未被标记为雷的方格都打开(所以如果你标记错的话,一起打开的时候会显示你游戏已经GG了)。

其他也没啥好说的了,感觉关注我的小伙伴应该都挺聪明的,自己看代码就能看懂吧。
定义完这些游戏中必要的元素类之后就在游戏主函数里实例化它们:

# 实例化游戏地图
minesweeper_map = MinesweeperMap(cfg, images)
position = (cfg.SCREENSIZE[0] - int(cfg.GRIDSIZE * 1.25)) // 2, (cfg.GRIDSIZE * 2 - int(cfg.GRIDSIZE * 1.25)) // 2
emoji_button = EmojiButton(images, position=position)
fontsize = font.size(str(cfg.NUM_MINES))
remaining_mine_board = TextBoard(str(cfg.NUM_MINES), font, (30, (cfg.GRIDSIZE*2-fontsize[1])//2-2), cfg.RED)
fontsize = font.size('000')
time_board = TextBoard('000', font, (cfg.SCREENSIZE[0]-30-fontsize[0], (cfg.GRIDSIZE*2-fontsize[1])//2-2), cfg.RED)
time_board.is_start = False

然后写个游戏主循环以根据用户的操作来更新当前的游戏状态就ok啦:

# 游戏主循环
clock = pygame.time.Clock()
while True:screen.fill(cfg.BACKGROUND_COLOR)# --按键检测for event in pygame.event.get():if event.type == pygame.QUIT:pygame.quit()sys.exit()elif event.type == pygame.MOUSEBUTTONDOWN:mouse_pos = event.posmouse_pressed = pygame.mouse.get_pressed()minesweeper_map.update(mouse_pressed=mouse_pressed, mouse_pos=mouse_pos, type_='down')elif event.type == pygame.MOUSEBUTTONUP:minesweeper_map.update(type_='up')if emoji_button.rect.collidepoint(pygame.mouse.get_pos()):minesweeper_map = MinesweeperMap(cfg, images)time_board.update('000')time_board.is_start = Falseremaining_mine_board.update(str(cfg.NUM_MINES))emoji_button.setstatus(status_code=0)# --更新时间显示if minesweeper_map.gaming:if not time_board.is_start:start_time = time.time()time_board.is_start = Truetime_board.update(str(int(time.time() - start_time)).zfill(3))# --更新剩余雷的数目显示remianing_mines = max(cfg.NUM_MINES - minesweeper_map.flags, 0)remaining_mine_board.update(str(remianing_mines).zfill(2))# --更新表情if minesweeper_map.status_code == 1:emoji_button.setstatus(status_code=1)if minesweeper_map.openeds + minesweeper_map.flags == cfg.GAME_MATRIX_SIZE[0] * cfg.GAME_MATRIX_SIZE[1]:minesweeper_map.status_code = 1emoji_button.setstatus(status_code=2)# --显示当前的游戏状态地图minesweeper_map.draw(screen)emoji_button.draw(screen)remaining_mine_board.draw(screen)time_board.draw(screen)# --更新屏幕pygame.display.update()clock.tick(cfg.FPS)

效果图
这个是开始界面,也就是我们开始能够看到的界面

扫雷的过程

扫雷完成的结果大家可以自己去试试哟~
有啥疑问或者大家有啥不懂的可以在评论下方评论的哈,也可以私信小编的哟~~

那个只能在win7的扫雷游戏,你能通关吗?今天用Python教大家,上号!!!相关推荐

  1. python趣味编程-扫雷游戏

    在上一期我们用Python实现了一个弹跳球的游戏,这一期我们继续使用Python实现一个简单的弹跳球游戏,让我们开始今天的旅程吧~ Python中的扫雷游戏GUI免费源代码 这 Python中的扫雷游 ...

  2. 公用计算机打不开扫雷,win7系统自带扫雷游戏打不开的解决方法

    win7系统使用久了,好多网友反馈说win7系统自带扫雷游戏打不开的问题,非常不方便.有什么办法可以永久解决win7系统自带扫雷游戏打不开的问题,面对win7系统自带扫雷游戏打不开故障问题,我们只需要 ...

  3. 如何用计算机玩扫雷,扫雷怎么玩_玩好扫雷游戏的技巧是什么【图文】-太平洋电脑网PConline-太平洋电脑网...

    扫雷怎么玩,扫雷技巧是什么,如何玩好扫雷游戏?这三大疑问一直是Win7扫雷游戏爱好者最想弄明白的.扫雷是每台电脑上都会自带的游戏,这款游戏虽然简单,但是却会吸引很多人去玩,但是看着一个一个的方格,却不 ...

  4. python扫雷 广度优先_Leetcode之广度优先搜索(BFS)专题-529. 扫雷游戏(Minesweeper)...

    Leetcode之广度优先搜索(BFS)专题-529. 扫雷游戏(Minesweeper) BFS入门详解:Leetcode之广度优先搜索(BFS)专题-429. N叉树的层序遍历(N-ary Tre ...

  5. c语言扫雷游戏代码_C语言游戏详解---扫雷游戏

    扫雷游戏大家应该都不陌生,一个扫雷游戏要满足的基本要求是: 1. 第一次扫的位置不能是雷 2. 每展开一个位置要显示该位置周围雷的个数 3. 若该位置周围没雷,要把周围展开 该游戏的界面是10X10的 ...

  6. [安全攻防进阶篇] 一.什么是逆向分析、逆向分析应用及经典扫雷游戏逆向

    从2019年7月开始,我来到了一个陌生的专业--网络空间安全.初入安全领域,是非常痛苦和难受的,要学的东西太多.涉及面太广,但好在自己通过分享100篇"网络安全自学"系列文章,艰难 ...

  7. c语言简单的模拟坐标,C语言模拟实现简单扫雷游戏

    本文指的扫雷是简单模拟电脑中的扫雷游戏,但以我目前的水平,也就只能在黑框中实现 test.c #include #include #include #include "game2.h&quo ...

  8. java扫雷具有win7_Win7系统自带扫雷游戏打不开的解决方法

    现如今很多游戏玩机都喜欢玩英雄联盟等这些大型网络游戏,但是win7 64位系统自带扫雷游戏也是有人玩的,在空闲无聊或无网络的时候偶尔玩玩该游戏还是不错的选择.细心的用户发现Win7系统自带扫雷游戏打不 ...

  9. 一文教你从零开始设计并实现一个Java扫雷游戏

    背景:扫雷这款游戏有着很长的历史,从扫雷被开发出来到现在进行了无数次的优化,这款游戏变得越来越让人爱不释手了,简单的玩法在加上一个好看的游戏界面,每一处的细节都体现了扫雷的魅力.以JAVA语言作为开发 ...

  10. LeetCode 529. 扫雷游戏(广度优先搜索BFS/深度优先搜索DFS)

    文章目录 1. 题目 2. 解题 2.1 BFS 2.2 DFS 1. 题目 让我们一起来玩扫雷游戏! 给定一个代表游戏板的二维字符矩阵. 'M' 代表一个未挖出的地雷, 'E' 代表一个未挖出的空方 ...

最新文章

  1. 机器学习常见的几个误区--逻辑回归的变量之间如果线性相关
  2. Android 70道面试题汇总不再愁面试
  3. Php在线字体woff转svg,在线字体格式转换ttf/otf/eot/woff/woff2格式工具
  4. 【收藏备用】服务器基本故障及排查方法
  5. 【大话数据结构算法】归并排序
  6. 学习Vue.js实战(一)
  7. 编写Web前端代码的注意事项
  8. xe DateTimePicker.Date bug
  9. cpu矿工cpuminer-multi编译与使用
  10. SQL:union \union all、intersect 、except的用法
  11. python教程我要自学网-我要自学网--json 数据解析-python。
  12. Java网络爬虫实操(6)
  13. 计算机职业规划作文1000字左右,职业生涯规划_1000字
  14. python实现电脑自动开机_python自动循环定时开关机(非重启)测试
  15. Linux字符终端用鼠标移动一个红色矩形
  16. C#用NPOI控件把MySQL数据库中查询符合条件的数据导出到EXCEL
  17. 桌面上的计算机打不开怎么办,电脑桌面计算机打不开怎么办
  18. 制作maven模板框架
  19. session活化与钝化
  20. c++nullptr(空指针常量)、constexpr(常量表达式)

热门文章

  1. CDN学习笔记二(技术详解)
  2. 大学生爱情兵法-洪亚非-听课笔记
  3. 非常好的油画制作软件ArtRage.v2.11
  4. 算法分析与设计:棋盘覆盖问题(分治法)
  5. 安装包制作工具 SetupFactory 详解
  6. 渣男论(跟技术无关,随笔而已)——一蓑烟雨任平生
  7. php 动态生成网站地图,DedeCMS网站地图动态生成方法
  8. lammps运行Linux,Lammps安装教程
  9. 网易云接口获取音乐(转载练习)
  10. 购票系统c语言座位分配,铁路购票系统的简单座位分配算法