我们已经实现了:
下面就可以实例化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即可
当然,这个游戏还没有计分升级的功能,这就留给大家自行研究和实现!
老规矩:代码及资源