- Python
pygame [扫雷3]
- 2024-6-15 19:33:57 @
1 条评论
-
mrhowe SU @ 2024-6-15 19:57:43
import sys import time,random import pygame from pygame.locals import * from enum import Enum ''' 增加计时和暂停 ''' BLOCK_WIDTH = 30 # 棋盘的宽度方块个数 BLOCK_HEIGHT = 15 # 棋盘的高度方块个数 SIZE = 30 # 方块的长宽 MINE_COUNT = 70 # 雷的数量 # 游戏屏幕的宽 SCREEN_WIDTH = BLOCK_WIDTH * SIZE # 游戏屏幕的高 SCREEN_HEIGHT = (BLOCK_HEIGHT + 2) * SIZE def load_img(file,size): img = pygame.image.load(file).convert() return pygame.transform.smoothscale(img,(size,size)) # 定义方块类 class Mine: def __init__(self, row, column, value=0): self.row = row self.column = column self.pos = (self.column * SIZE, (self.row + 2) * SIZE) self.value = value # 1:雷 0:安全 self.status = BlockStatus.normal self.around_mine_count = -1 # 周围雷的数量 self.image = load_img('resources/normal.jpg',SIZE) def __repr__(self): return str(self.value) # 定义雷区 class MineBlock: def __init__(self): # 生成方块棋盘组成列表,无地雷,每个方块是一个Mine实例() # 在 ipython 等终端中展示一下结果,有一个直观印象。 # 列表推导式的用法 self.blocks = [Mine(i, j) for i in range(BLOCK_HEIGHT) for j in range(BLOCK_WIDTH)] # 埋雷 # 在总方块里随机选MINE_COUNT个数,做雷。 mines = random.sample(range(BLOCK_WIDTH * BLOCK_HEIGHT), MINE_COUNT) for i in mines: self.blocks[i].value = 1 # 返回指定行列的 mine 对象 def getmine(self, row, column): return self.blocks[row * BLOCK_WIDTH + column] def get_around(self,row,column): return [(i,j) for i in range(max(row - 1, 0), min(row + 2, BLOCK_HEIGHT)) for j in range(max(column-1,0),min(column+2,BLOCK_WIDTH)) if not(i == row and j == column)] def open_mine(self, r, c): mine = self.getmine(r,c) #返回指定行列的 mine 对象 if mine.status == BlockStatus.normal: # 判断方块的状态是否为未点击 if mine.value: # mine.value # 1:雷 0:安全 mine.status = BlockStatus.bomb # 是雷把这个方块状态更改为# 踩中地雷 for m in self.blocks: # 遍历所有方块 if m.value == 1: # 找到所有是雷的方块 m.image = load_img("resources/mine.bmp", SIZE) # 把方块的图片更新为普通地雷 mine.image = load_img("resources/bomb.bmp", SIZE) #把踩到的方块的图片更新为红色地雷 return False # 结束游戏 mine.status = BlockStatus.opened # 如果不是地雷,就把方块状态更改为打开 around = self.get_around(r, c) # 调用get_around()找到这个方块的所有朋友 sum = 0 # 定义一个累加器变量记录朋友中有多少个地雷 for i, j in around: # 遍历所有朋友,是地雷就sum加一 if self.getmine(i, j).value == 1: sum += 1 mine.around_mine_count = sum # around_mine_count 更新mine方块周围雷的数量 if sum == 0: # 判断mine方块周围雷的数量是否为0 mine.image = load_img("resources/blank.bmp", SIZE) # 把mine方块图片设置为空 for i ,j in around: # 遍历所有朋友 if self.getmine(i,j).around_mine_count == -1: #如果朋友周围雷数量为-1就打开它 self.open_mine(i,j) elif mine.around_mine_count == -1: pass else: mine.image = load_img(f"resources/{mine.around_mine_count}.bmp", SIZE) return True def print_text(screen, font, x, y, text, fcolor=(255, 255, 255)): imgText = font.render(text, True, fcolor) screen.blit(imgText, (x, y)) class BlockStatus(Enum): normal = 1 # 未点击 opened = 2 # 已点击 mine = 3 # 地雷 flag = 4 # 标记为地雷 ask = 5 # 标记为问号 bomb = 6 # 踩中地雷 class GameStatus(Enum): ready = 1 start = 2 over = 3 win = 4 def main(): pygame.init() screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT)) pygame.display.set_caption('扫雷') bgcolor = (225, 225, 225) # 背景色 font1 = pygame.font.Font('resources/msyh.ttf', SIZE * 2) # 得分的字体 fwidth, fheight = font1.size('999') # 具体的文本 999 的宽和高 red = (200, 40, 40) block = MineBlock() game_status = GameStatus.ready flag_count = 0 start_time = pause_time = spend_time = 0 # 导入face图片 face_size = int(SIZE * 1.25) img_face_normal = load_img("resources/face_normal.bmp",face_size) img_face_fail = load_img("resources/face_fail.bmp",face_size) img_face_win = load_img("resources/face_win.bmp",face_size) face_pos_x = (SCREEN_WIDTH - face_size) // 2 face_pos_y = (SIZE * 2 - face_size) // 2 while True: # 填充背景色 screen.fill(bgcolor) open_count = 0 for mine in block.blocks: screen.blit(mine.image, mine.pos) if mine.value == 0 and mine.around_mine_count != -1: open_count += 1 if open_count == BLOCK_WIDTH * BLOCK_HEIGHT - MINE_COUNT: game_status = GameStatus.win screen.blit(img_face_normal,(face_pos_x,face_pos_y)) if game_status == GameStatus.win: screen.blit(img_face_win,(face_pos_x,face_pos_y)) print_text(screen,font1,face_pos_x+face_size+20,(SIZE * 2 - fheight)//2,"win!",red) elif game_status == GameStatus.over: screen.blit(img_face_fail,(face_pos_x,face_pos_y)) print_text(screen,font1,face_pos_x+face_size+20,(SIZE * 2 - fheight)//2,"lose!",red) # 显示剩余旗子和所用时间 if game_status == GameStatus.start: spend_time = int(time.time() - start_time - pause_time) print_text(screen,font1,30,(SIZE * 2 - fheight)//2, f"{spend_time}",red) # 用时 elif game_status == GameStatus.ready and spend_time == 0: print_text(screen,font1,30,(SIZE * 2 - fheight)//2, "0",red) else: print_text(screen,font1,30,(SIZE * 2 - fheight)//2, f"{spend_time}",red) flag_left = max(MINE_COUNT - flag_count, 0) print_text(screen,font1,SCREEN_WIDTH-fwidth,(SIZE * 2 - fheight)//2,f"{flag_left}",red) # 剩余雷 for event in pygame.event.get(): if event.type == QUIT: pygame.quit() sys.exit() elif event.type == MOUSEBUTTONDOWN: mouse_x, mouse_y = event.pos column = mouse_x // SIZE row = mouse_y // SIZE - 2 # 有上面的非雷区 b1, b2, b3 = pygame.mouse.get_pressed() elif event.type == MOUSEBUTTONUP: # 雷区 if row >= 0: mine = block.getmine(row, column) if game_status == GameStatus.ready: game_status = GameStatus.start start_time = time.time() if game_status == GameStatus.start: # 点击左键 if b1 and not b3: if not block.open_mine(row,column): game_status = GameStatus.over # 点击右键 elif not b1 and b3: if mine.status == BlockStatus.normal: mine.status = BlockStatus.flag mine.image = load_img("resources/flag.bmp", SIZE) flag_count += 1 elif mine.status == BlockStatus.flag: mine.status = BlockStatus.ask mine.image = load_img("resources/ask.bmp", SIZE) flag_count -= 1 elif mine.status == BlockStatus.ask: mine.status = BlockStatus.normal mine.image = load_img("resources/normal.jpg", SIZE) # 点击笑脸 elif face_pos_x < mouse_x < face_pos_x + face_size and \ face_pos_y < mouse_y < face_pos_y + face_size: # 暂停 if game_status == GameStatus.start: game_status = GameStatus.ready pause_start = time.time() elif game_status == GameStatus.ready and spend_time != 0: game_status = GameStatus.start pause_end = time.time() pause_time += int(pause_end - pause_start) # 重新开始 elif game_status == GameStatus.win or game_status == GameStatus.over: game_status = GameStatus.ready block = MineBlock() flag_count = 0 start_time = pause_time = spend_time = 0 pygame.display.update() if __name__ == '__main__': main()
- 1