每当用户按键时,都将在Pygame中注册一个事件。事件都是通过方法pygame.event.get() 获取的,因此在函数check_events() 中,我们需要指定要检查哪些类型的事 件。
每次按键都被注册为一个KEYDOWN 事件。
检测到KEYDOWN 事件时,我们需要检查按下的是否是特定的键。例如,如果按下的是右箭头键,我们就增大飞船的rect.centerx 值,将飞船向右移动:
game_functions.py
import sys
import pygame
def check_events(ship):
""" 响应键盘和鼠标事件"""
for event in pygame.event.get():
if event.type==pygame.QUIT:
sys.exit()
elif event.type==pygame.KEYDOWN:
if event.key==pygame.K_RIGHT:
#飞船右移动1像素
ship.rect.centerx+=1
def update_screen(ai_settings,screen,ship):
#更新屏幕上的图像,并切换到新屏幕
screen.fill(ai_settings.bg_color)
ship.blitme()
#让最近绘制的屏幕可见
pygame.display.flip()
alien_invasion.py
import pygame
from settings import Settings
from ship import Ship
import game_functions as gf
def run_game():
#初始化游戏并且创建一个屏幕对象
pygame.init()
ai_settings=Settings()
screen=pygame.display.set_mode(
(ai_settings.screen_width,ai_settings.screen_height))
pygame.display.set_caption("Alien Invasion")
#创建一艘飞船
ship=Ship(screen)
#开始游戏主循环
while True:
gf.check_events(ship)
gf.update_screen(ai_settings,screen,ship)
run_game()
对ship.py进行修改:
在方法__init__() 中,我们添加了属性self.moving_right ,并将其初始值设置为False 。
接下来,我们添加了方法update() ,它在前述标志为True 时向 右移动飞船。
import pygame
class Ship():
def __init__(self,screen):
""" 初始化飞船并设置其初始位置"""
self.screen=screen
#加载飞船图像并获取其他外接矩形
self.image=pygame.image.load('images/ship.bmp')
self.rect=self.image.get_rect()
self.screen_rect=screen.get_rect()
#将每艘新飞船放在屏幕底部中央
self.rect.centerx=self.screen_rect.centerx
self.rect.bottom=self.screen_rect.bottom
#移动标志
self.moving_right=False
def update(self):
""" 根据移动标志调整飞船位置"""
if self.moving_right:
self.rectt.centerx+=1
def blitme(self):
""" 在指定位置绘制飞船"""
self.screen.blit(self.image,self.rect)
修改game_functions.py
我们修改了游戏在玩家按下右箭头键时响应的方式:不直接调整飞船的位置,而只是将moving_right 设置为True 。
添加了一个新的elif 代码块,用 于响应KEYUP 事件:玩家松开右箭头键(K_RIGHT )时,我们将moving_right 设置为False 。
def check_events(ship):
""" 响应键盘和鼠标事件"""
for event in pygame.event.get():
if event.type==pygame.QUIT:
sys.exit()
elif event.type==pygame.KEYDOWN:
if event.key==pygame.K_RIGHT:
ship.moving_right=True
elif event.type==pygame.KEYUP:
if event.key==pygame.K_RIGHT:
ship.moving_right=False
def update_screen(ai_settings,screen,ship):
--snip--
最后,我们需要修改alien_invasion.py 中的while 循环,以便每次执行循环时都调用飞船的方法update() :
#开始游戏主循环
while True:
gf.check_events(ship)
ship.update()
gf.update_screen(ai_settings,screen,ship)
飞船的位置将在检测到键盘事件后(但在更新屏幕前)更新。这样,玩家输入时,飞船的位置将更新,从而确保使用更新后的位置将飞船绘制到屏幕上。
我们将再次修改Ship 类和函数check_events() 。下面显示了对Ship 类的方法__init__() 和update() 所做 的相关修改:
class Ship():
def __init__(self,screen):
""" 初始化飞船并设置其初始位置"""
--snip--
#移动标志
self.moving_right=False
self.moving_left=False
def update(self):
""" 根据移动标志调整飞船位置"""
if self.moving_right:
self.rect.centerx+=1
if self.moving_left:
self.rect.centerx-=1
一个细节: update()方法中用了两个if,而不是elif。
两个if的用意是,当玩家同时按下左右箭头的时候能够保持位置不变。
若用elif则右箭始终处于优先的状态
gane_functions.py
def check_events(ship):
""" 响应键盘和鼠标事件"""
for event in pygame.event.get():
if event.type==pygame.QUIT:
sys.exit()
elif event.type==pygame.KEYDOWN:
if event.key==pygame.K_RIGHT:
ship.moving_right=True
elif event.key==pygame.K_LEFT:
ship.moving_left=True
elif event.type==pygame.KEYUP:
if event.key==pygame.K_RIGHT:
ship.moving_right=False
elif event.key==pygame.K_LEFT:
ship.moving_left=False
每次执行while 循环时,飞船最多移动1像素,但我们可以在Settings 类中添加属性ship_speed_factor ,用于控制飞船的速度。我们将根据这个属性决定飞船在 每次循环时最多移动多少距离。
在settings.py中添加这个新属性:
self.ship_speed_factor=1.5
需要移动飞船时,我们将移动1.5像素而不是1像素。
class Settings():
""" 存储《外星人入侵》的所有设置的类"""
def __init__(self):
--snip--
#飞船的设置
self.ship_speed_factor=1.5
rect 的centerx 等属性只能存储整数值,因此我们需要对Ship 类做些修改:
import pygame
class Ship():
① def __init__(self,ai_settings,screen):
""" 初始化飞船并设置其初始位置"""
self.screen=screen
② self.ai_settings=ai_settings
#加载飞船图像并获取其他外接矩形
--snip--
#将每艘新飞船放在屏幕底部中央
--snip--
③ #在飞船的属性center中存储小数值
self.center=float(self.rect.centerx)
#移动标志
--snip--
def update(self):
""" 根据移动标志调整飞船位置"""
#更新飞船的centerx值,而不是rect
④ if self.moving_right:
self.center+=self.ai_settings.ship_speed_factor
if self.moving_left:
self.center-=self.ai_settings.ship_speed_factor
⑤ #根据self.center更新rect对象
self.rect.centerx=self.center
def blitme(self):
""" 在指定位置绘制飞船"""
self.screen.blit(self.image,self.rect)
alien_invasion.py
#创建一艘飞船
ship=Ship(ai_settings,screen)
为了让飞船到达屏幕边缘后停止移动,我们将修改Ship 类的方 法update() :
ship.py
def update(self):
""" 根据移动标志调整飞船位置"""
#更新飞船的centerx值,而不是rect
if self.moving_right and self.rect.right<self.screen_rect.right:
self.center+=self.ai_settings.ship_speed_factor
if self.moving_left and self.rect.left>0:
self.center-=self.ai_settings.ship_speed_factor
#根据self.center更新rect对象
self.rect.centerx=self.center
self.rect.right 返回飞船外接矩形的右边缘的 x 坐标,如果这个值小于self.screen_rect.right 的值, 就说明飞船未触及屏幕右边缘。左边缘的情况与此类似:如果rect 的左边缘的 x 坐标大于零,就说明飞船未触及屏幕左边缘。
这确保仅当飞船在屏幕内时, 才调整self.center 的值。
def check_keydown_events(event,ship):
""" 响应按键"""
if event.type==pygame.K_RIGHT:
ship.moving_right=True
elif event.type==pygame.K_LEFT:
ship.moving_left=True
def check_keyup_events(event,ship):
""" 响应松开"""
if event.type==pygame.K_RIGHT:
ship.moving_right=False
elif event.type==pygame.K_LEFT:
ship.moving_left=False
def check_events(ship):
"""响应按键和鼠标事件"""
for event in pygame.event.get():
if event.type==pygame.QUIT:
sys.exit()
elif event.type==pygame.KEYDOWN:
check_keydown_events(event,ship)
elif event.type==pygame.KEYUP:
check_keyup_events(event,ship)