Pygame 外星人入侵(3)
目录
引言
到这里为止,我们已经可以在一个 Pygame 游戏屏幕上绘制并显示出一架飞船了,且飞船的位置是我们所心仪的。
那么在这部分,我们要对现有的代码做一下重构。目的是简化主模块的代码量。
一、重构事件循环
在 https://blog.csdn.net/qq_32740521/article/details/107626753第一篇博文中,我们在游戏主模块的主循环中写入了一段事件循环代码,作用是不断响应玩家鼠标和键盘的命令,在那里,我们只对玩家关闭游戏的行为做了响应。
但是随着游戏功能的逐渐丰满,我们会要求响应更多的事件,比如鼠标左键点击某个按钮,或者键盘敲击了某个按键。因此,事件响应这一部分的代码,我们考虑用一个函数来进行封装,并且将函数的代码放到另外的模块中去。
1、自定义模块 game_functions
game_functions 模块专门用来存放我们在主模块中复杂的代码,用函数进行封装。
现在我们将事件循环的代码封装到自定义模块中去。
2、封装函数 check_events()
函数的命名要求能见名知意,这个循环的代码所实现的功能就是不断检查事件,因此得名 chcek_events。
现在我们将代码封装到函数中去.
game_functions.py
"""
专门用于存放主模块中复杂的代码,将其封装成一个个函数来使用
"""
import pygame
# 事件循环中有退出游戏的功能,因此需要导入sys模块
import sys
def check_events():
"""
事件检测循环,持续检测来自鼠标、键盘的请求,并作出相应的相应
"""
# 循环监视事件的发生
for event in pygame.event.get():
# 当玩家点击关闭按钮时,退出游戏
if event.type == pygame.QUIT:
sys.exit()
3、主模块代码缩减
由于我们已经在 game_functions 模块中封装了事件循环的函数 check_events(),所以主模块中的代码得以缩减。
我们这里要做的有如下几件事:
1、将主模块中原来的事件循环代码删除
2、在主模块中导入 game_functions 模块
3、由于 game_functions 模块中已经导入了 sys 模块,因此可以删除主模块中的 sys 导入代码
4、在原来事件循环的代码处,运行 check_events()函数。
此时的主模块代码:
import pygame
# 导入设置类,存放着我们要用到的所有设置参数
from settings import Settings
# 从ship模块中导入飞船类,用以创建飞船
from ship import Ship
# 从 game_functions 模块中导入所有函数,以供使用
from game_functions import *
# 游戏的主逻辑都在 run_game()函数中运行
def run_game():
# 初始化 pygame
pygame.init()
# 初始化设置类,得到所有我们要用到的设置参数值
my_setting = Settings()
# 绘制游戏窗口 screen,所有的游戏元素都在这个窗口里运动交互
screen = pygame.display.set_mode(size=(my_setting.screen_width, my_setting.screen_height))
# 修改游戏窗口的标题,这里当然是‘外星人入侵’
pygame.display.set_caption(my_setting.screen_title)
# 初始化飞船对象,创建一架飞船
my_ship = Ship(screen)
# 游戏主循环,使得循环中的代码可以不断循环执行
while True:
# 事件检测,现在我们已经将事件循环的代码封装到函数中了,直接运行即可
check_events()
# 为纯黑的游戏屏幕填充上不一样的颜色
screen.fill(my_setting.background_color)
# 在背景之上绘制我们的飞船,注意这里的逻辑,必须是飞船在背景之后绘制,确保飞船在背景的上层
my_ship.blitme()
# 刷新屏幕,使得元素能够不断刷新位置
pygame.display.flip()
# 运行游戏主逻辑
run_game()
将来我们如果要增加事件响应的种类和数量,就可以直接在 game_functions 模块下的 check_events() 函数中做修改。
二、重构屏幕更新
1、封装函数 update_screen()
同样,在主模块中,我们将屏幕背景、飞船都一起绘制到了游戏屏幕上,并进行了刷新,这一块代码在游戏主循环中是一定要一直不断执行的,不然会像我在第一篇博文中那样,屏幕一闪即消失。
基于这种情况,我们可以考虑将这部分代码也封装到函数中,并存放到另一个模块中。
def update_screen(screen, setting, ship):
# 为纯黑的游戏屏幕填充上不一样的颜色
screen.fill(setting.background_color)
# 在背景之上绘制我们的飞船,注意这里的逻辑,必须是飞船在背景之后绘制,确保飞船在背景的上层
ship.blitme()
# 刷新屏幕,使得元素能够不断刷新位置
pygame.display.flip()
2、主模块代码缩减
这里我们要做的修改很少,因为刚才在缩减事件循环时已经做了一些
1、删除主模块中原本填充背景色、绘制飞船、刷新屏幕的代码。
2、在删除代码的位置使用封装好的 update_screen() 函数。
import pygame
# 导入设置类,存放着我们要用到的所有设置参数
from settings import Settings
# 从ship模块中导入飞船类,用以创建飞船
from ship import Ship
# 从 game_functions 模块中导入所有函数,以供使用
from game_functions import *
# 游戏的主逻辑都在 run_game()函数中运行
def run_game():
# 初始化 pygame。使其可以绘制屏幕
pygame.init()
# 初始化设置类,得到所有我们要用到的设置参数值
my_setting = Settings()
# 绘制游戏窗口 screen,所有的游戏元素都在这个窗口里运动交互
screen = pygame.display.set_mode(size=(my_setting.screen_width, my_setting.screen_height))
# 修改游戏窗口的标题,这里当然是‘外星人入侵’
pygame.display.set_caption(my_setting.screen_title)
# 初始化飞船对象,创建一架飞船
my_ship = Ship(screen)
# 游戏主循环,使得循环中的代码可以不断循环执行
while True:
# 事件检测,现在我们已经将事件循环的代码封装到函数中了,直接运行即可
check_events()
# 绘制游戏画面,包括屏幕\背景、飞船,并将内容显示到游戏屏幕上
update_screen(screen, my_setting, my_ship)
# 运行游戏主逻辑
run_game()
至此,我们主模块的代码行数是 38 行(Pycharm提示根据PEP8,有些地方需要空行,这些地方需要空多少我都空出来了),且逻辑更加明了。
三、小结
与第一篇博文类似,书中作者一直在不断地给我们灌输大型项目中应该保持的思想,不断教给我们重构代码、封装代码的思想。我觉得这是很值得学习与借鉴的。
虽然没有功能上的增加,但是项目整体的结构更加丰满,不同模块之间的分工开始明确了;主模块中的代码得到了缩减,且之后的一些功能也会增加到其他模块中,主模块保持一个很少的代码量。