python实现《扫雷》小游戏

        童叟无欺啊,主程序绝对不到60行(而且还是算上那种空行的喔)!!!

        (文章末尾添加了代码文件下载链接,需要的可自取。)

        废话不多说,简简单单的讲一哈过程。

        1.画横线,竖线分出格子(拜托,小编。这是个人都知道的好吧,就不能挑重点讲一讲吗!···)

        2.创立一个20*20的数组,全部初始化为0,表示一张空白游戏地图

        3.随机在地图内生成40个地雷(代码实现中使用X代替),每生成一个地雷时都要将它周围的方格(不是地雷的方格)的数字加1。

        4.建立一个管理未被点开的格子的类,使用列表存储下所有还未被点开的格子的坐标,在鼠标单击一个格子后判断单机位置的合法性,若合法,则将这个鼠标点击的格子的坐标从列表中移除,代表格子被点开过,每次更新屏幕时都是根据这个列表中的元素来画出相对应的格子覆盖物。

        5.建立一个管理被点开格子的类,使用一个列表存储下所有被点开过的格子的坐标,根据2中的数组来画出对应的图案(如果对应数字为0,那就什么都不要画,显示出背景色就好)。

        6.每当点开一个格子,要是数字为0的话就用宽度搜索,将与他直接相连的数字为0的格子全部展现出来

        好了,多余的事情我就不想说了,更详细的解释都是在对应代码处以注解的形式呈现。

代码伺候。

        不信你自己数,加上所有的空行,主程序(保命的家伙不能丢!)最后一行也才第59行(这波属实是刀尖上舔血了!!!)

        (二次更改的时候才加的5行背景音乐就不算了吧···)

import sys   #调用exit()函数来结束游戏

import pygame

from covers import Cover    #未点击方块时表面的覆盖物
from map_of_game import Map   #游戏方块里面的地图
from settings import setting  #游戏参数设置


class Game:
        """管理游戏的主程序"""

        def __init__(self):
                pygame.init()
                pygame.mixer.init()
                self.setting = setting()

                #创立游戏主界面
                self.screen = pygame.display.set_mode(self.setting.screen_size)
                self.screen_rect = self.screen.get_rect()
                pygame.display.set_caption('扫雷')

                self.covers = Cover(self.setting, self.screen)  #表面覆盖物
                self.maps = Map(self.setting, self.covers, self.screen)  # 内部地图

                #背景音乐
                #pygame.mixer.music.load('data/bgmusic.wav')
                #pygame.mixer.music.play()
                #pygame.mixer.music.fadeout(3)



        def run_game(self):
                while True:
                        #if not pygame.mixer.music.get_busy():
                        #       pygame.mixer.music.play()
                        self._event_check_()  #检测事件
                        self._update_screen_()  #更新屏幕

        def _event_check_(self):
                for event in pygame.event.get():
                        if event.type == pygame.QUIT:  #结束游戏
                                sys.exit()
                        elif event.type == pygame.MOUSEBUTTONDOWN:
                                x, y = pygame.mouse.get_pos()  #检测到单击鼠标事件,将鼠标的位置传入
                                self.covers.delete(x, y) #删除对应方块上的覆盖物
                                self.maps.add(x, y)  #将该位置的覆盖物下的游戏地图加入即将要显示的队伍中

        def _update_screen_(self):

                self.screen.fill(self.setting.background_color) #填充背景颜色

                for i in range(25): #绘制方格
                        pygame.draw.line(self.screen, self.setting.line_color, [0, i * 25], [500, i * 25],
                                         self.setting.line_width) #横线
                        pygame.draw.line(self.screen, self.setting.line_color, [i * 25, 0], [i * 25, 500],
                                         self.setting.line_width) #竖线

                self.maps.show()   #将所有被点击过的方格下的数字展现出来
                self.covers.show() #将还没有被点击过的数字展现出来

                pygame.display.update()  #更新屏幕显示,将上面所做的工作展现在游戏界面上


if __name__ == '__main__':
        my_game = Game()
        my_game.run_game()

class setting:
        """管理游戏中的参数的类"""

        def __init__(self):
                self.screen_size = (500, 500)  # 屏幕大小
                self.background_color = (255, 255, 255)  # 背景色
                self.line_width = 1  # 线条粗细
                self.line_color = (120, 120,120)  # 线条颜色
                self.block_width = 24 #每一个方格的宽度
                self.screen_color = (150, 150, 150)  # 展示界面的颜色

import pygame


class Cover:
        """管理游戏覆盖物的类"""
        def __init__(self, setting, screen):  #游戏参数设置和游戏主界面
                self.setting = setting
                self.screen = screen

                self.covers = []  # 存储未被点击过的方块的覆盖物的位置
                for i in range(20):
                        for j in range(20):
                                self.covers.append([i, j])  #刚开始时整个界面都是被覆盖的

        def delete(self, x, y):  #传入单机鼠标的位置,判断是否合法,如果是,删除当前方块
                x = x // 25
                y = y // 25
                if [x, y] in self.covers:
                        self.covers.remove([x, y])

        def show(self):  #将所有未被点击过的方块展现出来
                for cur in self.covers:
                        pygame.draw.rect(self.screen, self.setting.screen_color, ((cur[0] * 25, cur[1] * 25), (24, 24)))

from random import randint

import pygame

from game_over import Over

from pygame.mixer import  *


class Map:
        """管理游戏中出现的雷和数字"""

        def __init__(self, setting, covers, screen): #游戏参数,游戏的覆盖物,游戏界面
                pygame.mixer.init()
                self.setting = setting
                self.bg_color = self.setting.background_color
                self.screen = screen
                self.covers = covers

                #踩雷的背景音乐
                #self.boot=pygame.mixer.Sound('data/boot.wav')
                #self.boot.set_volume(0.2)

                #开始时全部初始为0,表示当前方块啥都没有
                self.maps = [[0 for _ in range(20)] for _ in range(20)]

                #状态转移数组,所有(x+moves[i][0], y+moves[i][1])表示包围坐标为(x, y)方块的另外8块方块,
                #用于随机产生地雷后更新它周围方块上的数字
                self.moves = [[-1, -1], [0, -1], [1, -1], [-1, 0], [1, 0], [-1, 1], [0, 1], [1, 1]]

                #存储当前需要被显示出来数字方块
                self.now_show = []

                #点击到地雷后结束游戏
                self.over = Over(self.screen)

                #随机生成游戏地图
                self._born_map()

        def _born_map(self):
                """随机生成地图"""
                for i in range(40):
                        x = randint(0, 19)
                        y = randint(0, 19)
                        while self.maps[x][y] != 0:
                                x = randint(0, 19)
                                y = randint(0, 19)
                        self.maps[x][y] = 'X'
                        self._connect_(x, y) #更新地雷周围的数字

        def _connect_(self, x, y):
                """更新地雷周围数字的函数"""
                for cur in self.moves:
                        i = x + cur[0]
                        j = y + cur[1]
                        if i >= 0 and i < 20 and j >= 0 and j < 20 and self.maps[i][j] != 'X':
                                self.maps[i][j] += 1

        def add(self, x, y):  #传入当前鼠标点击的位置,判断合法性,合法则将对应的方块左边传入要展示的列表中
                i = x // 25
                j = y // 25
                if i >= 0 and i < 20 and j >= 0 and j < 20:
                        self.now_show.append([i, j])
                        if self.maps[i][j] == 0:
                                self._add_connect_(i, j)

                #如果当前点击到了地雷,将地雷标记为红色方块,并展示出来,暂停游戏3秒,自动退出游戏
                if self.maps[i][j] == 'X':
                        pygame.draw.rect(self.screen, (255, 0, 0), ((i * 25, j * 25), (25, 25)))
                        #self.boot.play()
                        self.over.show()

        # 宽度搜索将(x,y)周围相连的空白方块也展示出来
        def _add_connect_(self, x, y):
                que = []
                que.append([x, y])
                while que:
                        cur = que[-1]
                        del (que[-1])
                        for k in range(8):
                                i, j = cur[0] + self.moves[k][0], cur[1] + self.moves[k][1]
                                if i >= 0 and i < 20 and j >= 0 and j < 20 and self.maps[i][j] != 'X' and [i,
                                                                                                         j] not in self.now_show:
                                        self.now_show.append([i, j])
                                        self.covers.delete(i * 25, j * 25)
                                        if self.maps[i][j]==0:
                                                que.append([i, j])

        def show(self):
                """将生成的地图展现到屏幕上"""
                for cur in self.now_show:
                        i = cur[0]
                        j = cur[1]
                        if self.maps[i][j] == 0:
                                continue
                        else:
                                self.msg = str(self.maps[i][j])
                                self.font = pygame.font.SysFont(None, 45)
                                self.font_image = self.font.render(self.msg, True, (60, 0, 0), None)
                                self.image_ract = self.font_image.get_rect()
                                self.image_ract.x = i * 25
                                self.image_ract.y = j * 25
                                self.image_ract.width = 24
                                self.image_ract.height = 24
                                self.screen.blit(self.font_image, self.image_ract)

import sys  #结束游戏
from time import sleep  #暂停游戏

import pygame


class Over:
        """控制游戏结束的类"""
        def __init__(self, screen): #游戏主界面
                self.is_over = False
                self.screen = screen
                self.screen_rect = self.screen.get_rect()

                self.msg = 'GAME OVER'
                #渲染文字'GAME OVER'到游戏主界面上
                self.font = pygame.font.SysFont(None, 48)
                self.image = self.font.render(self.msg, True, (100, 0, 0), (0, 0, 60))
                self.rect = self.image.get_rect()
                self.rect.center = self.screen_rect.center  #将文字放在界面中心

        def show(self):  #遇见炸弹,游戏结束,结束前将玩家遇到的炸弹标记未红色方块并在结束前绘制出来
                self.screen.blit(self.image, self.rect)
                pygame.display.update()
                sleep(3)
                sys.exit()

都看到这里来了,都不能点个赞嘛!!!(呜呜呜)

代码源文件下载链接:

链接:https://pan.baidu.com/s/1dFjZ2nmtPH7BiYHt3WIpvQ 
提取码:1024

下载后直接运行main.py文件即可,其它文件均放在main.py的同级目录下。

猜你喜欢

转载自blog.csdn.net/qq_65120254/article/details/126470061