创建外星舰队
为了绘制一支舰队,我们需要弄清楚如何用外星人填充屏幕的上部,而不会使游戏窗口过度拥挤。有多种方法可以实现这一目标。我们将通过在屏幕顶部添加外星人来实现这一点,直到没有空间容纳新的外星人。然后我们将重复这个过程,只要我们有足够的垂直空间来添加新行。
创建一行外星人
现在我们准备好生成一整排外星人了。为了形成一整行,我们首先要制作一个外星人,这样我们就可以获得外星人的宽度。我们将在屏幕左侧放置一个外星人,然后不断添加外星人,直到空间用完:
def _create_fleet(self):
"""Create the fleet of aliens."""
# Create an alien and keep adding aliens until there's no room left.
# Spacing between aliens is one alien width.
alien = Alien(self)
alien_width = alien.rect.width
current_x = alien_width (1)
while current_x < (self.settings.screen_width - 2 * alien_width): (2)
new_alien = Alien(self) (3)
new_alien.x = current_x (4)
new_alien.rect.x = current_x
self.aliens.add(new_alien)
current_x += 2 * alien_width (5)
我们从创建的第一个外星人中获取外星人的宽度,然后定义一个名为 current_x 的变量❶。 这是指我们打算放置在屏幕上的下一个外星人的水平位置。 我们最初将其设置为一个外星人宽度,以从屏幕左边缘偏移舰队中的第一个外星人。
接下来,我们开始 while 循环❷;只要有足够的空间放置外星人,我们就会继续添加外星人。 为了确定是否有空间放置另一个外星人,我们将 current_x 与某个最大值进行比较。 定义此循环的第一次尝试可能如下所示:
while current_x < self.settings.screen_width:
这看起来似乎可行,但它会将最后一个外星人放在屏幕最右边缘的行中。所以我们在屏幕右侧添加一点边距。 只要屏幕右边缘至少有两个外星人宽度的空间,我们就进入循环并向舰队添加另一个外星人。
每当有足够的水平空间来继续循环时,我们要做两件事:在正确的位置创建一个外星人,并定义该行中下一个外星人的水平位置。 我们创建一个外星人并将其分配给 new_alien ❸。 然后我们将精确的水平位置设置为 current_x ❹ 的当前值。我们还将外星人的矩形定位在相同的 x 值处,并将新的外星人添加到 self.aliens 组中。
最后,我们增加 current_x ❺ 的值。 我们在水平位置添加两个外星人宽度,以移过我们刚刚添加的外星人,并在外星人之间留出一些空间。 Python 将在 while 循环开始时重新评估条件,并决定是否还有空间容纳另一个外星人。 当没有剩余空间时,循环就会结束,我们应该有一整排外星人。
现在运行 Alien Invasion 时,您应该会看到第一行外星人出现,如图 13-3 所示。

如何构建像本节所示的循环并不总是很明显。 编程的一个好处是,您对于如何解决此类问题的最初想法不一定是正确的。 在外星人位置太靠右的情况下开始这样的循环是完全合理的,然后修改循环直到屏幕上有适当的空间。 |
重构 _create_fleet()
如果我们到目前为止编写的代码是创建舰队所需的全部代码,那么我们可能会保留 _create_fleet() 不变。 但我们还有更多工作要做,所以让我们稍微清理一下该方法。 我们将添加一个新的辅助方法 _create_alien(),并从 _create_fleet() 调用它:
def _create_fleet(self):
--snip--
while current_x < (self.settings.screen_width - 2 * alien_width):
self._create_alien(current_x)
current_x += 2 * alien_width
def _create_alien(self, x_position): (1)
"""Create an alien and place it in the row."""
new_alien = Alien(self)
new_alien.x = x_position
new_alien.rect.x = x_position
self.aliens.add(new_alien)
_create_alien() 方法除了 self 之外还需要一个参数:指定外星人应该放置在哪里的 x 值❶。 _create_alien() 主体中的代码与 _create_fleet() 中的代码相同,只是我们使用参数名称 x_position 代替 current_x。 这种重构将使添加新行和创建整个队列变得更加容易。
添加多行外星人
为了完成舰队,我们将继续添加更多行,直到空间用完为止。 我们将使用嵌套循环——我们将在当前循环周围包裹另一个 while 循环。内循环将通过关注外星人的 x 值将外星人水平排成一行。外循环将通过关注 y 值来垂直放置外星人。当我们接近屏幕底部时,我们将停止添加行,为飞船留出足够的空间,并留出一些空间开始向外星人开火。
以下是如何在 _create_fleet() 中嵌套两个 while 循环:
def _create_fleet(self):
"""Create the fleet of aliens."""
# Create an alien and keep adding aliens until there's no room left.
# Spacing between aliens is one alien width and one alien height.
alien = Alien(self)
alien_width, alien_height = alien.rect.size (1)
current_x, current_y = alien_width, alien_height (2)
while current_y < (self.settings.screen_height - 3 * alien_height): (3)
while current_x < (self.settings.screen_width - 2
* alien_width):
self._create_alien(current_x, current_y) (4)
current_x += 2 * alien_width
# Finished a row; reset x value, and increment y value. (5)
current_x = alien_width
current_y += 2 * alien_height
我们需要知道外星人的高度才能放置行,因此我们使用外星人矩形(rect)的大小属性来获取外星人的宽度和高度❶。 矩形的大小(size)属性是包含其宽度和高度的元组。
接下来,我们为舰队中第一个外星人的放置设置初始 x 和 y 值❷。 我们将其从左侧放置一个外星宽度,从顶部向下放置一个外星高度。 然后我们定义 while 循环来控制在屏幕上放置多少行❸。 只要下一行的 y 值小于屏幕高度减去三个外星高度,我们就会继续添加行。 (如果这没有留下适当的空间,我们可以稍后调整。)
我们调用 _create_alien(),并向其传递 y 值及其 x 位置❹。 我们稍后将修改 _create_alien()。
注意最后两行代码的缩进❺。 它们位于外部 while 循环内部,但位于内部 while 循环外部。 该块在内循环完成后运行; 它在每行创建后运行一次。 添加每一行后,我们重置 current_x 的值,以便下一行中的第一个外星人将被放置在与前一行中的第一个外星人相同的位置。 然后我们将两个外星人高度添加到 current_y 的当前值中,因此下一行将放置在屏幕的更下方。 缩进在这里非常重要; 如果在本节末尾运行 Alien_invasion.py 时没有看到正确的舰队,请检查这些嵌套循环中所有行的缩进。
我们需要修改 _create_alien() 以正确设置外星人的垂直位置:
def _create_alien(self, x_position, y_position):
"""Create an alien and place it in the fleet."""
new_alien = Alien(self)
new_alien.x = x_position
new_alien.rect.x = x_position
new_alien.rect.y = y_position
self.aliens.add(new_alien)
我们修改方法的定义以接受新外星人的 y 值,并在方法主体中设置矩形的垂直位置。 现在运行游戏时,您应该看到一队完整的外星人,如图 13-4 所示。

在下一部分中,我们将让舰队移动!