python+pygame实现扫雷游戏之三

我们已经实现了:

python+pygame实现扫雷游戏之一

python+pygame实现扫雷游戏之二

下面就可以实例化MineBlock及响应鼠标消息循环了。其本质就是不停地接收鼠标事件,改变二维数组的状态,然后“画”在屏幕上就可以了。

六、

main.py

# -*- coding: utf-8 -*-
import sys
import time
import pygame
from pygame.locals import *

from mineblock import *
from gamestatus import *


# 游戏屏幕的宽
SCREEN_WIDTH = BLOCK_WIDTH * SIZE
# 游戏屏幕的高
SCREEN_HEIGHT = (BLOCK_HEIGHT + 2) * SIZE   #要留出上面的位置显示剩余地雷的数量和用时。


def print_text(screen, font, x, y, text, fcolor=(255, 255, 255)):
    imgText = font.render(text, True, fcolor)
    screen.blit(imgText, (x, y))


def main():
    pygame.init()
    screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
    pygame.display.set_caption('扫雷')

    font1 = pygame.font.Font('resources/bdm.TTF', SIZE * 2)  # 地雷数量、事件的字体
    fwidth, fheight = font1.size('888')
    fontcolor = (208, 38, 38)

    # 加载资源图片,因为资源文件大小不一,所以smoothscale做了统一的缩放处理
    img0 = pygame.image.load('resources/0.bmp').convert()
    img0 = pygame.transform.smoothscale(img0, (SIZE, SIZE))
    img1 = pygame.image.load('resources/1.bmp').convert()
    img1 = pygame.transform.smoothscale(img1, (SIZE, SIZE))
    img2 = pygame.image.load('resources/2.bmp').convert()
    img2 = pygame.transform.smoothscale(img2, (SIZE, SIZE))
    img3 = pygame.image.load('resources/3.bmp').convert()
    img3 = pygame.transform.smoothscale(img3, (SIZE, SIZE))
    img4 = pygame.image.load('resources/4.bmp').convert()
    img4 = pygame.transform.smoothscale(img4, (SIZE, SIZE))
    img5 = pygame.image.load('resources/5.bmp').convert()
    img5 = pygame.transform.smoothscale(img5, (SIZE, SIZE))
    img6 = pygame.image.load('resources/6.bmp').convert()
    img6 = pygame.transform.smoothscale(img6, (SIZE, SIZE))
    img7 = pygame.image.load('resources/7.bmp').convert()
    img7 = pygame.transform.smoothscale(img7, (SIZE, SIZE))
    img8 = pygame.image.load('resources/8.bmp').convert()
    img8 = pygame.transform.smoothscale(img8, (SIZE, SIZE))
    img_blank = pygame.image.load('resources/blank.bmp').convert()
    img_blank = pygame.transform.smoothscale(img_blank, (SIZE, SIZE))
    img_flag = pygame.image.load('resources/flag.bmp').convert()
    img_flag = pygame.transform.smoothscale(img_flag, (SIZE, SIZE))
    img_ask = pygame.image.load('resources/ask.bmp').convert()
    img_ask = pygame.transform.smoothscale(img_ask, (SIZE, SIZE))
    img_mine = pygame.image.load('resources/mine.bmp').convert()
    img_mine = pygame.transform.smoothscale(img_mine, (SIZE, SIZE))
    img_blood = pygame.image.load('resources/blood.bmp').convert()
    img_blood = pygame.transform.smoothscale(img_blood, (SIZE, SIZE))
    img_error = pygame.image.load('resources/error.bmp').convert()
    img_error = pygame.transform.smoothscale(img_error, (SIZE, SIZE))
    face_size = int(SIZE * 1.25)
    img_face_fail = pygame.image.load('resources/face_fail.bmp').convert()
    img_face_fail = pygame.transform.smoothscale(img_face_fail, (face_size, face_size))
    img_face_normal = pygame.image.load('resources/face_normal.bmp').convert()
    img_face_normal = pygame.transform.smoothscale(img_face_normal, (face_size, face_size))
    img_face_success = pygame.image.load('resources/face_success.bmp').convert()
    img_face_success = pygame.transform.smoothscale(img_face_success, (face_size, face_size))
    face_pos_x = (SCREEN_WIDTH - face_size) // 2
    face_pos_y = (SIZE * 2 - face_size) // 2

    img_dict = {
        0: img0,
        1: img1,
        2: img2,
        3: img3,
        4: img4,
        5: img5,
        6: img6,
        7: img7,
        8: img8
    }

    bgcolor = (225, 225, 225)   # 背景色

    block = MineBlock()
    game_status = GameStatus.readied
    start_time = None   # 开始时间
    elapsed_time = 0    # 耗时

    while True:
        # 填充背景色
        screen.fill(bgcolor)

        for event in pygame.event.get():
            if event.type == QUIT:
                sys.exit()
            elif event.type == MOUSEBUTTONDOWN:
                mouse_x, mouse_y = event.pos
                x = mouse_x // SIZE
                y = mouse_y // SIZE - 2
                bLeft, bMiddle, bRight = pygame.mouse.get_pressed()
                if game_status == GameStatus.started:
                    # 鼠标左右键同时按下,如果已经标记了所有雷,则打开周围一圈
                    # 如果还未标记完所有雷,则有一个周围一圈被同时按下的效果
                    if bLeft and bRight:
                        mine = block.getmine(x, y)
                        if mine.status == BlockStatus.opened:
                            if not block.double_mouse_button_down(x, y):
                                game_status = GameStatus.over
            elif event.type == MOUSEBUTTONUP:
                if y < 0:
                    if face_pos_x <= mouse_x <= face_pos_x + face_size \
                            and face_pos_y <= mouse_y <= face_pos_y + face_size:
                        game_status = GameStatus.readied
                        block = MineBlock()
                        start_time = time.time()
                        elapsed_time = 0
                        continue

                if game_status == GameStatus.readied:
                    game_status = GameStatus.started
                    start_time = time.time()
                    elapsed_time = 0

                if game_status == GameStatus.started:
                    mine = block.getmine(x, y)
                    if bLeft and not bRight:       # 按鼠标左键
                        if mine.status == BlockStatus.normal:
                            if not block.open_mine(x, y):
                                game_status = GameStatus.over
                    elif not bLeft and bRight:     # 按鼠标右键
                        if mine.status == BlockStatus.normal:
                            mine.status = BlockStatus.flag
                        elif mine.status == BlockStatus.flag:
                            mine.status = BlockStatus.ask
                        elif mine.status == BlockStatus.ask:
                            mine.status = BlockStatus.normal
                    elif bLeft and bRight:
                        if mine.status == BlockStatus.double:
                            block.double_mouse_button_up(x, y)

        flag_count = 0
        opened_count = 0

        for row in block.block:
            for mine in row:
                pos = (mine.x * SIZE, (mine.y + 2) * SIZE)
                if mine.status == BlockStatus.opened:
                    screen.blit(img_dict[mine.around_mine_count], pos)
                    opened_count += 1
                elif mine.status == BlockStatus.double:
                    screen.blit(img_dict[mine.around_mine_count], pos)
                elif mine.status == BlockStatus.bomb:
                    screen.blit(img_blood, pos)
                elif mine.status == BlockStatus.flag:
                    screen.blit(img_flag, pos)
                    flag_count += 1
                elif mine.status == BlockStatus.ask:
                    screen.blit(img_ask, pos)
                elif mine.status == BlockStatus.hint:
                    screen.blit(img0, pos)
                elif game_status == GameStatus.over and mine.value:
                    screen.blit(img_mine, pos)
                elif mine.value == 0 and mine.status == BlockStatus.flag:
                    screen.blit(img_error, pos)
                elif mine.status == BlockStatus.normal:
                    screen.blit(img_blank, pos)

        print_text(screen, font1, 28, (SIZE * 2 - fheight) // 2 - 2, '%02d' % (MINE_COUNT - flag_count), fontcolor)
        if game_status == GameStatus.started:
            elapsed_time = int(time.time() - start_time)
        print_text(screen, font1, SCREEN_WIDTH - fwidth - 8, (SIZE * 2 - fheight) // 2 - 2, '%03d' % elapsed_time, fontcolor)

        if flag_count + opened_count == BLOCK_WIDTH * BLOCK_HEIGHT:
            game_status = GameStatus.win

        if game_status == GameStatus.over:
            screen.blit(img_face_fail, (face_pos_x, face_pos_y))
        elif game_status == GameStatus.win:
            screen.blit(img_face_success, (face_pos_x, face_pos_y))
        else:
            screen.blit(img_face_normal, (face_pos_x, face_pos_y))

        pygame.display.update()


if __name__ == '__main__':
    main()


#pygame.mouse.get_pressed()  ——  获取鼠标按键的情况(是否被按下)
#返回一个由布尔值组成的列表,代表所有鼠标按键被按下的情况。True意味着在调用此方法时该鼠标按键正被按下
#(1, 0, 1)  表示左键和右键被按下(左键、中键、右键)

#pygame.mouse.get_pos()  ——  获取鼠标光标的位置
#返回鼠标光标的坐标 (x, y)。这个坐标以窗口左上角为基准点

# pygame.mouse.get_rel()  ——  获取鼠标与前一位置的偏移量

# pygame.mouse.set_pos(pos)  ——  设置鼠标光标的位置
#如果鼠标光标是可视的,则光标将会跳到新的坐标上。移动鼠标将会产生一个新的 pygame.MOUSEMOTION 事件

# pygame.mouse.set_visible(bool)  ——  隐藏或显示鼠标光标 
# b=pygame.mouse.set_visible(False)  #设置鼠标是否可见    True 可见,False 不可见
# 返回值:返回在设置之前的状态

# pygame.mouse.get_focused()  ——  检查程序界面是否获得鼠标焦点
# 当 pygame 正在接受鼠标输入事件(即说,鼠标正在处于“active”或“focus”状态)返回值为 True

# pygame.mouse.set_cursor()  ——  设置鼠标光标在程序内的显示图像
# pygame.mouse.get_cursor()  ——  获取鼠标光标在程序内的显示图像

# flip函数和update函数的主要区别在于它们处理屏幕重绘的方式和效率。‌
# flip函数:‌flip函数会重新绘制整个屏幕对应的窗口。‌这意味着,‌无论屏幕上哪个部分是否发生变化,‌flip函数都会导致整个屏幕被重新绘制。‌\
# 这种方式适用于需要快速、‌完全更新屏幕内容的情况,‌例如在场景变化非常频繁的游戏中。‌
# update函数:‌相比之下,‌Update函数仅重新绘制窗口中有变化的区域。‌如果屏幕上只有少数物体在移动或变化,‌update函数只会重绘那些实际移动或变化的部分,‌而不会重绘没有变化的部分。‌\
# 这种方式能够提高效率,‌因为它减少了不必要的屏幕重绘操作,‌从而可能提供更好的性能,‌尤其是在场景变化不是非常频繁的情况下。‌
# 总的来说,flip函数适用于需要快速、‌完全更新屏幕内容的场景,‌而update函数则更适合于只需要更新屏幕部分内容的场景,‌特别是在性能优化方面有要求的情况下。‌

结合代码理解一下逻辑:

6.1  一直到bgcolor = (225, 225, 225)   # 背景色这里,都是一些资源的加载,没有太多需要理解的

6.2 先实例化MineBlock的对象为block,将游戏状态设为准备好了GameStatus.readied,开始时间,耗时等初始化工作

6.3  消息循环

     6.3.1  QUIT

     6.3.2  鼠标按下,游戏场景中只需要监测左右键同时按下事件,对应的是MineBlock中的                           double_mouse_button_down函数

     6.3.3 鼠标弹起,

             6.3.3.1  鼠标在笑脸的地方,重玩游戏

             6.3.3.2  GameStatus.readied改成GameStatus.started后,只左键弹起,对应的是                             MineBlock中的open_mine函数

             6.3.3.3  鼠标右键弹起,走马灯效果状态转换:normal--flag--ask--normal

             6.3.3.4  左右键同时弹起,对应的是MineBlock中的double_mouse_button_up函数

 6.4  前面都是返回的状态,接下来就将状态和显示的图片资源结合起来,即哪个坐标的状态           对应哪个图片,将整个屏幕在内存中blit出来

6.5  最后pygame.display.update即可

当然,这个游戏还没有计分升级的功能,这就留给大家自行研究和实现!

老规矩:代码及资源

  • 8
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,下面是一个简单的扫雷游戏实现,使用Pythonpygame库: ```python import pygame import random # 初始化游戏 pygame.init() # 设置游戏窗口尺寸 WIDTH = 500 HEIGHT = 600 WINDOW_SIZE = (WIDTH, HEIGHT) # 设置游戏窗口标题 pygame.display.set_caption("扫雷游戏") # 定义常用颜色 BLACK = (0, 0, 0) WHITE = (255, 255, 255) GRAY = (128, 128, 128) RED = (255, 0, 0) GREEN = (0, 255, 0) BLUE = (0, 0, 255) YELLOW = (255, 255, 0) # 定义游戏区域尺寸和格子数量 GRID_SIZE = 20 GRID_NUM = int(WIDTH / GRID_SIZE) # 定义雷区和雷数量 mines = [] mine_num = 50 # 创建游戏窗口 screen = pygame.display.set_mode(WINDOW_SIZE) # 创建字体对象 font = pygame.font.SysFont(None, 40) # 创建游戏结束标志 game_over = False # 生成随机雷区 def generate_mines(): global mines # 随机生成雷的位置 for i in range(mine_num): mine = (random.randint(0, GRID_NUM - 1), random.randint(0, GRID_NUM - 1)) while mine in mines: mine = (random.randint(0, GRID_NUM - 1), random.randint(0, GRID_NUM - 1)) mines.append(mine) # 计算每个格子周围的雷数 def count_mines(x, y): count = 0 for i in range(-1, 2): for j in range(-1, 2): if (x + i, y + j) in mines: count += 1 return count # 绘制游戏界面 def draw_game(): global game_over # 绘制游戏区域 screen.fill(WHITE) for i in range(GRID_NUM): for j in range(GRID_NUM): pygame.draw.rect(screen, GRAY, (i * GRID_SIZE, j * GRID_SIZE, GRID_SIZE, GRID_SIZE), 1) if (i, j) in mines and not game_over: pygame.draw.circle(screen, BLACK, (i * GRID_SIZE + GRID_SIZE // 2, j * GRID_SIZE + GRID_SIZE // 2), GRID_SIZE // 4) elif (i, j) not in mines and not game_over: count = count_mines(i, j) if count > 0: text = font.render(str(count), True, BLUE) screen.blit(text, (i * GRID_SIZE + GRID_SIZE // 2 - text.get_width() // 2, j * GRID_SIZE + GRID_SIZE // 2 - text.get_height() // 2)) # 绘制游戏结束信息 if game_over: text = font.render("Game Over", True, RED) screen.blit(text, (WIDTH // 2 - text.get_width() // 2, HEIGHT // 2 - text.get_height() // 2)) # 刷新屏幕 pygame.display.flip() # 主循环 generate_mines() while True: for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() exit() elif event.type == pygame.MOUSEBUTTONDOWN: if not game_over: x, y = pygame.mouse.get_pos() i, j = x // GRID_SIZE, y // GRID_SIZE if (i, j) in mines: game_over = True else: count = count_mines(i, j) if count == 0: # 连续翻开空白格子 visited = set() queue = [(i, j)] while queue: x, y = queue.pop(0) visited.add((x, y)) for m in range(-1, 2): for n in range(-1, 2): if 0 <= x + m < GRID_NUM and 0 <= y + n < GRID_NUM and (x + m, y + n) not in visited: count = count_mines(x + m, y + n) if count == 0: queue.append((x + m, y + n)) elif count > 0: visited.add((x + m, y + n)) for x, y in visited: if (x, y) not in mines: count = count_mines(x, y) if count > 0: text = font.render(str(count), True, BLUE) screen.blit(text, (x * GRID_SIZE + GRID_SIZE // 2 - text.get_width() // 2, y * GRID_SIZE + GRID_SIZE // 2 - text.get_height() // 2)) pygame.draw.rect(screen, WHITE, (x * GRID_SIZE, y * GRID_SIZE, GRID_SIZE, GRID_SIZE)) else: # 翻开数字格子 text = font.render(str(count), True, BLUE) screen.blit(text, (i * GRID_SIZE + GRID_SIZE // 2 - text.get_width() // 2, j * GRID_SIZE + GRID_SIZE // 2 - text.get_height() // 2)) pygame.draw.rect(screen, WHITE, (i * GRID_SIZE, j * GRID_SIZE, GRID_SIZE, GRID_SIZE)) else: game_over = False mines.clear() generate_mines() draw_game() ``` 这个程序使用了Pygame库来实现,可以直接运行,生成一个简单的扫雷游戏界面。其中,generate_mines()函数用于随机生成雷区,count_mines(x, y)函数用于计算每个格子周围的雷数,draw_game()函数用于绘制游戏界面,主循环监听鼠标事件,根据用户的操作来更新游戏状态和界面。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值