1.回顾项目:重构代码(添加一个结束游戏的快捷键Q),本章涉及游戏功能如下。
1.屏幕左上角添加一个外星人,指定合适的边距;
2.根据第一个外星人和屏幕尺寸计算屏幕需要容纳多少个外星人,循环创建外星人填满屏幕;
3.让外星人群想两边和下方移动,直到外星人被全部击落,若整群外星人被击落则再创建一群外星人,若外星人撞到飞船或抵达屏幕底端,则销毁飞船并再创建一群外星人;
4.限制玩家可用飞船数量,配给的飞船用完后,游戏结束。
2.创建第一个外星人:与放置飞船类似,将外星人的位图文件保存在文件夹images中。创建alien.py文件,定义Alien类,该类继承pygame.sprite导入的Sprite类,其他设置与Ship类相似。game_function模块中update_screen()函数中添加绘制外星人的代码。
alien.bmp 图像文件如下:
alien.py 代码如下:
# -*- coding: GBK -*-
import pygame
from pygame.sprite import Sprite
class Alien(Sprite):
'''表示单个外星人的类'''
def __init__(self, ai_settings, screen):
'''初始化外星人并设置其起始位置'''
super().__init__()
self.screen = screen
self.ai_settings = ai_settings
# 加载外星人图像,并设置其rect属性
self.image = pygame.image.load('images/alien.bmp')
self.rect = self.image.get_rect()
# 每个外星人最初都在屏幕左上角附近
self.rect.x = self.rect.width
self.rect.y = self.rect.height
# 存储外星人的准确位置
self.x = float(self.rect.x)
def blitme(self):
'''在指定位置绘制外星人'''
self.screen.blit(self.image, self.rect)
game_functions.py 代码如下:
# -*- coding: GBK -*-
import sys # 使用模块sys来退出游戏。
import pygame
from bullet import Bullet
def check_keydown_events(event, ai_settings, screen, ship, bullets):
'''响应按键'''
if event.key == pygame.K_RIGHT:
ship.moving_right = True
elif event.key == pygame.K_LEFT:
ship.moving_left = True
elif event.key == pygame.K_SPACE: # 空白键
fire_bullet(ai_settings, screen, ship, bullets)
elif event.key == pygame.K_q: # 字母Q键
sys.exit()
def fire_bullet(ai_settings, screen, ship, bullets):
'''如果还没有到达限制,就发射一颗子弹'''
# 创建一颗新子弹,并将其加入到编组bullets中
if len(bullets) < ai_settings.bullets_allowed: # 限制子弹数量
new_bullet = Bullet(ai_settings, screen, ship)
bullets.add(new_bullet)
def check_keyup_events(event, ship):
'''响应松开'''
if event.key == pygame.K_RIGHT:
ship.moving_right = False
elif event.key == pygame.K_LEFT:
ship.moving_left = False
def check_events(ai_settings, screen, ship, bullets):
'''响应按键和鼠标事件'''
# 监视键盘和鼠标事件
for event in pygame.event.get(): #Pygame检测到的时间
if event.type == pygame.QUIT: #玩家单击窗口关闭按钮,则检测到pygame.QUIT事件。
sys.exit() #退出游戏
elif event.type == pygame.KEYDOWN: #根据按住键修改移动标志的值
check_keydown_events(event, ai_settings, screen, ship, bullets)
elif event.type == pygame.KEYUP: #根据松开键修改移动标志的值
check_keyup_events(event, ship)
def update_screen(ai_settings, screen, ship, alien, bullets):
'''更新屏幕上的图像,并切换到新屏幕'''
# 每次循环时都重绘屏幕
screen.fill(ai_settings.bg_color) #screen.fill()只接受一个实参:一种颜色
# 在飞船和外星人后面重绘所有子弹
for bullet in bullets.sprites(): #方法bullets.sprites()返回一个列表,其中包含编组bullets中的所有精灵
bullet.draw_bullet()
ship.blitme() #在指定位置绘制飞船
alien.blitme() #在指定位置绘制外星人
# 让最近绘制的屏幕可见
pygame.display.flip() #不断更新屏幕,以显示元素的新位置
def update_bullets(bullets):
'''更新子弹的位置,并删除已消失子弹'''
# 更新每一粒子弹的位置
bullets.update() #对编组调用update(),编组自动对其中每个精灵调用update(),即为每一粒子弹调用bullet.update()
# 删除已消失子弹
for bullet in bullets.copy(): # 遍历编组的副本
if bullet.rect.bottom <= 0:
bullets.remove(bullet)
# print(len(bullets)) # 核实已消失子弹确实删除了
alien_invasion.py 执行代码如下:
# -*- coding: GBK -*-
import pygame # 模块pygame包含开发游戏所需的功能。
from settings import Settings # 导入设置模块的Setting类
from ship import Ship # 导入ship模块的Ship类,它负责管理飞船的大部分行为。
import game_functions as gf # 导入game_functions模块
from pygame.sprite import Group #用于创建子弹编组
from alien import Alien # 导入alien模块Alien类,控制每个外星人的行为
def run_game():
# 初始化游戏并创建一个屏幕对象
pygame.init() #初始化背景设置,让Pygame能够正确地工作。
ai_settings = Settings() #创建Settings实例,并使用它来访问设置
screen = pygame.display.set_mode((ai_settings.screen_width, ai_settings.screen_height)) #调用pygame.display.set_mode()来创建一个窗口,实参是一个元祖,指定游戏窗口尺寸。
pygame.display.set_caption("Alien Invasion") #设置窗口的标题
# 创建一艘飞船
ship = Ship(ai_settings, screen)
# 创建一个用于存储子弹的编组
bullets = Group()
# 创建一个外星人
alien = Alien(ai_settings, screen)
# 开始游戏的主循环
while True:
# 响应按键和鼠标事件
gf.check_events(ai_settings, screen, ship, bullets)
# 更新飞船的位置
ship.update()
# 更新子弹的位置,并删除已消失子弹
gf.update_bullets(bullets)
# 新屏幕上的图像,并切换到新屏幕
gf.update_screen(ai_settings, screen, ship, alien, bullets)
run_game()
3.创建一群外星人:需要确定一行可以容纳多少外星人(屏幕宽度减去两个外星人宽度alien_width得到可用宽度,因外星人之间间隔一个宽度,故可用宽度除以2个alien_width得到每行的外星人数量);外星人行数计算:屏幕高度减去飞船高度减去3个alien_height(1个上边缘间距,2个是飞船和外星人间隔距离)得到可用高度,故可用高度除以2个alien_height得到可容纳外星人行数。因Alien类继承了Sprite类,故也可创建外星人的编组。每创建一个外星人在计算属性rect值后添加至编组,对编组调用draw()时,Pygame自动绘制编组的每个元素,由元素的属性rect决定绘制位置。alien.draw(screen)表示在屏幕上绘制编组中的每个外星人。
game.functions.py 代码如下:
# -*- coding: GBK -*-
import sys # 使用模块sys来退出游戏。
import pygame
from bullet import Bullet
from alien import Alien # 导入alien模块Alien类,控制每个外星人的行为
def check_keydown_events(event, ai_settings, screen, ship, bullets):
'''响应按键'''
if event.key == pygame.K_RIGHT:
ship.moving_right = True
elif event.key == pygame.K_LEFT:
ship.moving_left = True
elif event.key == pygame.K_SPACE: # 空白键
fire_bullet(ai_settings, screen, ship, bullets)
elif event.key == pygame.K_q: # 字母Q键
sys.exit()
def fire_bullet(ai_settings, screen, ship, bullets):
'''如果还没有到达限制,就发射一颗子弹'''
# 创建一颗新子弹,并将其加入到编组bullets中
if len(bullets) < ai_settings.bullets_allowed: # 限制子弹数量
new_bullet = Bullet(ai_settings, screen, ship)
bullets.add(new_bullet)
def check_keyup_events(event, ship):
'''响应松开'''
if event.key == pygame.K_RIGHT:
ship.moving_right = False
elif event.key == pygame.K_LEFT:
ship.moving_left = False
def check_events(ai_settings, screen, ship, bullets):
'''响应按键和鼠标事件'''
# 监视键盘和鼠标事件
for event in pygame.event.get(): #Pygame检测到的时间
if event.type == pygame.QUIT: #玩家单击窗口关闭按钮,则检测到pygame.QUIT事件。
sys.exit() #退出游戏
elif event.type == pygame.KEYDOWN: #根据按住键修改移动标志的值
check_keydown_events(event, ai_settings, screen, ship, bullets)
elif event.type == pygame.KEYUP: #根据松开键修改移动标志的值
check_keyup_events(event, ship)
def update_screen(ai_settings, screen, ship, aliens, bullets):
'''更新屏幕上的图像,并切换到新屏幕'''
# 每次循环时都重绘屏幕
screen.fill(ai_settings.bg_color) #screen.fill()只接受一个实参:一种颜色
# 在飞船和外星人后面重绘所有子弹
for bullet in bullets.sprites(): #方法bullets.sprites()返回一个列表,其中包含编组bullets中的所有精灵
bullet.draw_bullet()
ship.blitme() #在指定位置绘制飞船
aliens.draw(screen) #对编组调用draw(),Pygame自动绘制编组的每个元素,绘制的位置由元素的属性rect决定。此处在屏幕上绘制编组中每个外星人。
# 让最近绘制的屏幕可见
pygame.display.flip() #不断更新屏幕,以显示元素的新位置
def update_bullets(bullets):
'''更新子弹的位置,并删除已消失子弹'''
# 更新每一粒子弹的位置
bullets.update() #对编组调用update(),编组自动对其中每个精灵调用update(),即为每一粒子弹调用bullet.update()
# 删除已消失子弹
for bullet in bullets.copy(): # 遍历编组的副本
if bullet.rect.bottom