Python学习之路日志—利用pygame开发《外星人入侵》游戏项目(2)
3.1 使用按键驾驶飞船:
下面来让玩家能够左右移动飞船。为此,我将编写代码,在用户按左或右箭头键时作出响应:
简要分析一下:
-
在函数
check_events()
中包含形参 ship ,因为玩家按右箭头键时,需要将飞船向右移动。 -
在函数
check_events()
内部,我在事件循环中添加了一个 elif 代码块,以便在Pygame检测到KEYDOWN 事件时作出响应(见13行)。读取属性event.key
,以检查按下的是否是右箭头键(pygame.K_RIGHT
)(见14行)。如果按下的是右键,就将ship.rect.centerx
的值加1,从而将飞船向右移动(见15行)。 -
在alien_invasion.py中,需要更新调用的
check_events()
代码,将ship 作为实参传递给它:
如下图所示,现在运行alien_invasion.py,则每按右箭头键一次,飞船都将向右移动1像素:
3.2 允许飞船不断移动:
玩家按住右箭头键不放时,我希望飞船不断地向右移动,直到玩家松开为止。我将让游戏检测pygame.KEYUP 事件,以便玩家松开右箭头键时程序能够知道这一点;然后,我将结合使用KEYDOWN 和 KEYUP 事件,以及一个名为 moving_right 的标志来实现持续移动。
飞船不动时,标志 moving_right 将为 False 。玩家按下右箭头键时,将这个标志设置为 True ;而玩家松开时,将这个标志重新设置为 False 。
飞船的属性都由 Ship 类控制,因此给这个类添加一个名为moving_right
的属性和一个名为update()
的方法。方法update()
检查标志 moving_right 的状态, 如果这个标志为 True ,就调整飞船的位置。每当需要调整飞船的位置时,都调用这个方法:
1.在方法__init__()
中,我添加了属性self.moving_right
,并将其初始值设置为False 。
2.接下来,添加方法update()
,它在前述标志为 True 时向右移动飞船(见21行)。
下面需要修改check_events()
,使其在玩家按下右箭头键时将moving_right
设置为 True ,并在玩家松开时将moving_right
设置为False :
在15行处,修改游戏在玩家按下右箭头键时响应的方式:不直接调整飞船的位置,而只是将moving_right
设置为 True 。在17行处,添加一个新的 elif 代码块,用于响应 KEYUP 事件:玩家松开右箭头键(K_RIGHT
)时,将moving_right
设置为 False 。
最后需要修改alien_invasion.py中的 while 循环,以便每次执行循环时都调用飞船的方法update()
:
如下图所示,如果现在运行alien_invasion.py并按住右箭头键,飞船将不断地向右移动,直到松开为止:
3.3 允许飞船左右移动:
飞船能够不断地向右移动后,添加向左移动的逻辑很容易。再次修改Ship类和函数check_events()
。下面显示了对 Ship 类的方法__init__()
和update()
所做的相关修改:
在方法__init__()
中,我添加了标志self.moving_left ;在方法update()
中,添加了一个 if 代码块而不是 elif 代码块,这样如果玩家同时按下了左右箭头键,将先增大飞船的rect.centerx
值,再降低这个值,即飞船的位置保持不变。如果使用一个 elif 代码块来处理向左移动的情况,右箭头键将始终处于优先地位。
还需对check_events()
作两方面的调整:
如果因玩家按下左键而触发了KEYDOWN事件,就将moving_left
设置为 True ;如果因玩家松开它而触发了 KEYUP 事件,就将moving_left
设置为 False 。这里之所以可以使用 elif 代码块,是因为每个事件都只与一个键相关联;如果玩家同时按下了左右箭头键,将检测到两个不同的事件。
如果此时运行alien_invasion.py,将能够不断地左右移动飞船;如果同时按左右箭头键,飞船将纹丝不动:
3.4 调整飞船移动速度:
当前,每次执行 while 循环时,飞船最多移动1像素,但可以通过在 Settings 类中添加属性ship_speed_factor
为一个具体数值,用于控制飞船的具体速度,然后还要对 Ship 类做些修改:
- 在第5行处,在
__init__()
的形参列表中添加了ai_settings
,让飞船能够获取其速度设置。 - 接下来的第8行,将形参
ai_settings
的值存储在一个属性中,以便能够在update()
中使用它。 - 为准确地存储飞船的位置,我定义了一个可存储小数值的新属性
self.center
(见19行处)。使用函数float()
将self.rect.centerx
的值转换为小数,并将结果存储到self.center
中。 - 现在在
update()
中调整飞船的位置时,将self.center
的值增加或减去ai_settings.ship_speed_factor
的值(见28行)。 - 更新
self.center
后再根据它来更新控制飞船位置的self.rect.centerx (见32行)。
在alien_invasion.py中创建 Ship 实例时,需要传入实参ai_settings
:
现在就可以根据需要控制飞船的移动速度了。
3.5 限制飞船活动范围:
当前,如果玩家按住箭头键的时间足够长,飞船将移到屏幕外面,消失得无影无踪。下面来修复这种问题,让飞船到达屏幕边缘后停止移动。为此,我将修改 Ship 类的方法update()
:
上述代码在修改self.center
的值之前检查飞船的位置。self.rect.right
返回飞船外接矩形的右边缘的 x 坐标,如果这个值小于self.screen_rect.right
的值, 就说明飞船未触及屏幕右边缘。
左边缘的情况与此类似:如果rect
的左边缘的 x 坐标大于零,就说明飞船未触及屏幕左边缘。这确保仅当飞船在屏幕内时, 才调整self.center
的值。
如果此时运行alien_invasion.py,飞船将在触及屏幕左边缘或右边缘后停止移动: