让外星舰队移动
现在让我们让外星人舰队在屏幕上向右移动,直到到达边缘,然后让它下降一定的量并向另一个方向移动。 我们将继续这一运动,直到所有外星人都被击落、其中一个与飞船相撞、或者一个到达屏幕底部。 让我们首先让舰队向右移动。
向右移动外星舰队
为了移动外星人,我们将在 alien.py 中使用 update() 方法,我们将为外星人组中的每个外星人调用该方法。首先,添加一个设置来控制每个外星人的速度:
def __init__(self):
--snip--
# Alien settings
self.alien_speed = 1.0
然后使用这个设置在 alien.py 中实现 update() :
def __init__(self, ai_game):
"""Initialize the alien and set its starting position."""
super().__init__()
self.screen = ai_game.screen
self.settings = ai_game.settings
--snip--
def update(self):
"""Move the alien to the right."""
self.x += self.settings.alien_speed (1)
self.rect.x = self.x (2)
我们在 __init__()
中创建一个 settings 参数,以便我们可以在 update() 中访问外星人的速度。每次我们更新外星人的位置时,我们都会将其向右移动 alien_speed 中存储的量。我们使用 self.x 属性来跟踪外星人的确切位置,该属性可以保存浮点值❶。然后我们使用 self.x 的值来更新外星人矩形的位置❷。
在主 while 循环中,我们已经调用了更新船舶和子弹位置的调用。 现在我们还将添加一个调用来更新每个外星人的位置:
while True:
self._check_events()
self.ship.update()
self._update_bullets()
self._update_aliens() (1)
self._update_screen()
self.clock.tick(60)
我们将要编写一些代码来管理舰队的移动,因此我们创建一个名为 _update_aliens() 的新方法。我们会在子弹更新后更新外星人的位置,因为我们很快就会检查是否有子弹击中外星人。
将此方法放置在模块中的位置并不重要。但为了保持代码的组织性,我将其放置在 _update_bullets() 之后,以匹配 while 循环中方法调用的顺序。这是 _update_aliens() 的第一个版本:
def _update_aliens(self):
"""Update the positions of all aliens in the fleet."""
self.aliens.update()
我们在 aliens 组上使用 update() 方法,该方法调用每个外星人的 update() 方法。当您现在运行外星人入侵时,您应该看到舰队向右移动并消失在屏幕一侧。
创建表示外星舰队移动方向的设置
现在,我们将创建相关设置,使舰队在撞击屏幕右边缘时,向下并向左移动。下面是实现这一行为的方法:
# Alien settings
self.alien_speed = 1.0
self.fleet_drop_speed = 10
# fleet_direction of 1 represents right; -1 represents left.
self.fleet_direction = 1
设置舰队下降速度(fleet_drop_speed
)可以控制每次外星人到达屏幕边缘时,舰队下降的速度。将这一速度与外星人的水平速度分开很有帮助,这样就可以独立调整这两个速度。
要实现舰队方向设置,我们可以使用 'left' 或 'right' 这样的文本值,但最终会使用 if-elif
语句测试舰队方向。相反,因为我们只需要处理两个方向,所以让我们使用值 1 和 -1 并在每次舰队改变方向时在它们之间切换。(使用数字也是有道理的,因为向右移动需要在每个外星人的 x 坐标值上做加法,而向左移动则需要从每个外星人的 x 坐标值上做减法)。
检查外星人是否到达了屏幕边缘
我们需要一个方法来检查异形是否位于任一边缘,我们还需要修改 update()
以允许每个外星人向适当的方向移动。这段代码是 Alien 类的一部分:
def check_edges(self):
"""Return True if alien is at edge of screen."""
screen_rect = self.screen.get_rect()
return (self.rect.right >= screen_rect.right) or (self.rect.left <= 0) (1)
def update(self):
"""Move the alien right or left."""
self.x += self.settings.alien_speed * self.settings.fleet_direction (2)
self.rect.x = self.x
我们可以对任何异形调用新方法 check_edges()
,查看它是位于左边缘还是右边缘。如果异形矩形的右属性大于或等于屏幕矩形的右属性,则该异形处于右边缘。如果它的左侧值小于或等于 0 ❶,则它位于左边缘。我们没有将条件测试放在 if 代码块中,而是直接将测试放在了返回语句中。如果异形位于右边缘或左边缘,该方法将返回 True;如果异形不在任一边缘,则返回 False。
我们修改 update()
方法,将异形的速度乘以舰队方向❷ 的值,从而允许向左或向右运动。如果舰队方向为 1,异形速度的值将加到异形的当前位置,使异形向右移动;如果舰队方向为 -1,异形速度的值将从异形的位置中减去,使异形向左移动。
向下移动外星舰队并改变移动方向
当一个外星人到达边缘时,整个舰队需要下降并改变方向。因此,我们需要在 AlienInvasion
中添加一些代码,因为我们要在这里检查是否有外星人处于左侧或右侧边缘。
我们将通过编写 _check_fleet_edges()
和 _change_fleet_direction()
方法,然后修改 _update_aliens()
方法来实现这一点。我会把这些新方法放在 _create_alien()
之后,但这些方法在类中的位置并不重要。
def _check_fleet_edges(self):
"""Respond appropriately if any aliens have reached a
n edge."""
for alien in self.aliens.sprites(): (1)
if alien.check_edges():
self._change_fleet_direction() (2)
break
def _change_fleet_direction(self):
"""Drop the entire fleet and change the fleet's direction."""
for alien in self.aliens.sprites():
alien.rect.y += self.settings.fleet_drop_speed (3)
self.settings.fleet_direction *= -1
在 _check_fleet_edges()
中,我们会对舰队进行循环,并在每个外星人❶上调用 check_edges()
。如果 check_edges()
返回 True
,我们就知道某个外星人处于边缘位置,整个舰队需要改变方向;因此我们调用 _change_fleet_direction()
并跳出循环❷。在 _change_fleet_direction()
中,我们会循环查看所有异形,并使用舰队下降速度❸的设置将每个异形下降;然后我们会将舰队方向的当前值乘以 -1,从而改变其值。改变舰队方向的这一行并不是 for
循环的一部分。我们想改变每个外星人的垂直位置,但只想改变舰队的方向一次。
下面是对 _update_aliens()
的修改:
def _update_aliens(self):
"""Check if the fleet is at an edge, then update positions."""
self._check_fleet_edges()
self.aliens.update()
我们修改了该方法,在更新每个外星人的位置之前调用 _check_fleet_edges()
。
现在运行游戏时,舰队应该会在屏幕边缘来回移动,并在每次撞到边缘时下降。现在,我们可以开始击落外星人,并留意是否有外星人击中飞船或到达屏幕底部。