当前位置: 首页 > article >正文

外星人入侵-Python-二

武装飞船

开发一个名为《外星人入侵》的游戏吧!为此将使用 Pygame,这是一组功能强大而有趣的模块,可用于管理图形、动画乃至声音, 让你能够更轻松地开发复杂的游戏。通过使用Pygame来处理在屏幕上绘制图像 等任务,可将重点放在程序的高级逻辑上。

你将安装Pygame,再创建一艘能够根据用户输入左右移动和射击的飞船。在接下来的两章,你将创建一群作为射杀目标的外星人,并改进该游戏:限制可供玩家使用的飞船数,并且添加记分牌。

玩家控制一艘最初出现在屏幕底部中央的飞船。玩 家可以使用箭头键左右移动飞船,还可使用空格键射击。游戏开始时,一群外 星人出现在天空中,并向屏幕下方移动。玩家的任务是射杀这些外星人。玩家 将所有外星人都消灭干净后,将出现一群新的外星人,其移动速度更快。只要 有外星人撞到玩家的飞船或到达屏幕底部,玩家就损失一艘飞船。玩家损失三 艘飞船后,游戏结束。

一.第二阶段、

首先在屏幕上边缘附近添加一个外星人,再生成一群外星人。然后让这群外星人向两边 和下面移动,并删除被子弹击中的外星人。最后,显示玩家拥有的飞船数量, 并在玩家的飞船用完后结束游戏。

  • 研究既有代码,确定实现新功能前是否要重构。
  • 在屏幕左上角添加一个外星人,并指定合适的边距。
  • 根据第一个外星人的边距和屏幕尺寸计算屏幕上可容纳多少个外星人。编写一 个循环来创建一系列外星人,使其填满屏幕的上半部分。
  • 让外星人群向两边和下方移动,直到外星人被全部击落、有外星人撞到飞船或 有外星人抵达屏幕底端。如果整群外星人都被击落,将再创建一群外星人。如 果有外星人撞到了飞船或抵达屏幕底端,将销毁飞船并再创建一群外星人。
  • 限制玩家可用的飞船数量。当配给的飞船用完之后,游戏将结束。

1.1创建第一个外星人

在屏幕上放置外星人与放置飞船类似。每个外星人的行为都由Alien 类控制,我们将像创建Ship 类那样创建这个类。

1.1.1创建 Alien 类

alien.py

import pygame
from pygame.sprite import Sprite
class Alien(Sprite):
  def __init__(self, ai_game): 
      """初始话外星人并设置其他位置"""
      super().__init__()
      self.screen = ai_game.screen
      
      #加载外星人图像并获取其外接矩形
      self.image = pygame.image.load('images/alien.bmp')
      self.rect = self.image.get_rect()
      
      #每个外星人最初都在屏幕左上角
      self.rect.x = self.rect.width               #1
      self.rect.y = self.rect.height
      
      #存储外星人的精确位置
      self.x = float(self.rect.x)                 #2
      

每个外星人最初都位于屏幕 左上角附近。将每个外星人的左边距都设置为外星人的宽度,并将上边距设置为外 星人的高度(#1),这样更容易看清。我们主要关心的是外星人的水平速度,因此 精确地记录了每个外星人的水平位置(#2)。 Alien 类不需要一个在屏幕上绘制外星人的方法,因为我们将使用一个Pygame编组 方法,自动在屏幕上绘制编组中的所有元素。

1.1.2 创建 Alien 实例

要让第一个外星人在屏幕上现身,需要创建一个Alien 实例。这属于设置工作,因 此将把这些代码放在AlienInvasion 类的方法__init__() 末尾。我们最终会创 建一群外星人,涉及的工作量不少,因此将新建一个名为_create_fleet() 的辅 助方法。

alien_invasion.py

--snip-- 
from bullet import Bullet 
from alien import Alien 
   def __init__(self): 
        --snip-- 
        self.ship = Ship(self) 
        self.bullets = pygame.sprite.Group() 
        self.aliens = pygame.sprite.Group() 
 
        self._create_fleet() 

创建了一个用于存储外星人群的编组,还调用了接下来将编写的方法 _create_fleet() 。

alien_invasion.py

   def _create_fleet(self): 
        """创建外星人群。""" 
        # 创建一个外星人。 
        alien = Alien(self) 
        self.aliens.add(alien) 

创建了一个Alien 实例,再将其添加到用于存储外星人群的编组中。

要让外星人现身,需要在_update_screen() 中对外星人编组调用方法draw() :

alien_invasion.py

def _update_screen(self): 
        --snip-- 
        for bullet in self.bullets.sprites(): 
            bullet.draw_bullet() 
        self.aliens.draw(self.screen) 
        pygame.display.flip() 

对编组调用draw() 时,Pygame将把编组中的每个元素绘制到属性rect 指定的位 置。方法draw() 接受一个参数,这个参数指定了要将编组中的元素绘制到哪个 surface上。

1.2 创建一群外星人

1.2.1 确定一行可容纳多少个外星人

们重写 _create_fleet() 使其创建一行外星人:

alien_invasion.py

    def _create_fleet(self):
        """创建外星人群。"""
        # 创建一个外星人并计算一行可容纳多少个外星人。
        # 外星人间距为外星人的宽度。
        alien = Alien(self)                                                #1
        alien_width= alien.rect.width                                      #2
        available_space_x = self.settings.screen_width - (2 * alien_width) #3 
        number_aliens_x = available_space_x // (2 * alien_width)
        # 创建第一行外星人。
        for alien_number in range(number_aliens_x):                        #4
            # 创建一个外星人并将其加入当前行。
            alien = Alien(self)
            alien.x= alien_width + 2 * alien_width * alien_number          #5
            alien.rect.x = alien.x
            self.aliens.add(alien)

为放置外星人,需要知道外星人的宽度和高度, 因此在执行计算前,创建一个外星人(#1)。这个外星人不是外星人群的成员,因此没有将其加入编组aliens 中。在(#2)处,从外星人的rect 属性中获取外星人宽度,并将这个值存储到alien_width 中,以免反复访问属性rect 。在❸处,计算 可用于放置外星人的水平空间以及其中可容纳多少个外星人。 接下来,编写一个循环,从零数到要创建的外星人数(#4)。在这个循环中,创建 一个新的外星人,并通过设置坐标将其加入当前行(#5)。将每个外星人都往右推一个外星人宽度。接下来,将外星人宽度乘以2,得到每个外星人占据的空间(其中包括右边的空白区域),再据此计算当前外星人在当前行的位置。我们使用外星 人的属性x 来设置其rect 的位置。最后,将每个新创建的外星人都添加到编组 aliens 中。

1.2.2重构 _create_fleet()

添加辅助方法_create_alien() ,并在_create_fleet() 中调用它:

alien_invasion.py

 def _create_fleet(self): 
        --snip-- 
        # 创建第一行外星人。 
        for alien_number in range(number_aliens_x): 
            self._create_alien(alien_number) 
    def _create_alien(self, alien_number): 
        """创建一个外星人并将其放在当前行。""" 
        alien = Alien(self) 
        alien_width = alien.rect.width 
        alien.x = alien_width + 2 * alien_width * alien_number 
        alien.rect.x = alien.x 
        self.aliens.add(alien) 

除self 外,方法_create_alien() 还接受另一个参数,即要创建的外星人的编 号。该方法的代码与_create_fleet() 相同,但在内部获取外星人宽度,而不是 将其作为参数传入。这样重构后,添加新行进而创建整群外星人将更容易。

1.2.3添加行

要创建外星人群,需要计算屏幕可容纳多少行,并将创建一行外星人的循环重复执 行相应的次数。为计算可容纳的行数,要先计算可用的垂直空间:用屏幕高度减去 第一行外星人的上边距(外星人高度)、飞船的高度以及外星人群最初与飞船之间 的距离(外星人高度的两倍):

alien_invasion.py

    def _create_fleet(self):
        """创建外星人群。"""
        # 创建一个外星人并计算一行可容纳多少个外星人。
        # 外星人间距为外星人的宽度。
        alien = Alien(self)
        alien_width, alien_height = alien.rect.size                        #1
        available_space_x = self.settings.screen_width - (2 * alien_width)
        number_aliens_x = available_space_x // (2 * alien_width)
        
        # 计算屏幕可容纳多少行外星人。
        ship_height = self.ship.rect.height
        available_space_y = (self.settings.screen_height -                #2
                             (3 * alien_height) - ship_height)
        number_rows = available_space_y // (2 * alien_height)
        
        # 创建外星人群。
        for row_number in range(number_rows):                             #3
            for alien_number in range(number_aliens_x):
                self._create_alien(alien_number,row_number)
        
    def _create_alien(self, alien_number, row_number):
        alien = Alien(self)
        alien_width, alien_height = alien.rect.size
        alien.x = alien_width + 2 * alien_width * alien_number
        alien.rect.x = alien.x
        alien.rect.y = alien.rect.height + 2 * alien.rect.height * row_number #4
        self.aliens.add(alien)

需要知道外星人的宽度和高度,在(#1)处使用了属性size 。该属性是一个元组, 包含rect 对象的宽度和高度。

为计算屏幕可容纳多少行外星人,在计算 available_space_x 的代码后面添加了计算available_space_y 的代码(#2)。此处将计算公式用圆括号括起来,以便将代码分成两行,。

为创建多行外星人,使用了两个嵌套在一起的循环:一个外部循环和一个内部循环 (#3)。内部循环创建一行外星人,而外部循环从零数到要创建的外星人行数: Python将重复执行创建单行外星人的代码,重复次数为number_rows 。 为嵌套循环,编写了一个新的for 循环,并缩进了要重复执行的代码。现在调用 _create_alien() 时,传递了一个表示行号的实参,将每行都沿屏幕依次向下放置。

在_create_alien() 的定义中,需要一个用于存储行号的形参。在 _create_alien() 中,修改外星人的坐标(#4)并在第一行外星人上方留出与外星人等高的空白区域。相邻外星人行的坐标相差外星人高度的两倍,因此将 外星人高度乘以2,再乘以行号。第一行的行号为0,因此第一行的垂直位置不变, 而其他行都沿屏幕依次向下放置。

1.3让外星人群移动

让外星人群在屏幕上向右移动,撞到屏幕边缘后下移一定的量,再沿相反的 方向移动。我们将不断移动所有的外星人,直到外星人被全部消灭,或者有外星人 撞上飞船或抵达屏幕底端。

1.3.1向右移动外星人群

为移动外星人群,将使用alien.py中的方法update() 。对于外星人群中的每个外 星人,都要调用它。首先,添加一个控制外星人速度的设置:

settings.py

def __init__(self, ai_game): 
          """初始化外星人并设置其初始位置。""" 
          super().__init__() 
          self.screen = ai_game.screen 
          self.settings = ai_game.settings 
          --snip-- 
 
      def update(self): 
          """向右移动外星人。""" 
          self.x += self.settings.alien_speed     #1
          self.rect.x = self.x                    #2

在__init__() 中添加了属性settings ,以便能够在update() 中访问外星人 的速度。每次更新外星人时,都将它向右移动,移动量为alien_speed 的值。使用属性self.x 跟踪每个外星人的准确位置,该属性可存储小数值(#1)。 然后,使用self.x 的值来更新外星人的rect 的位置(#2)

主while 循环中已调用了更新飞船和子弹的方法,现在还需更调用更新每个外星人 位置的方法: alien_invasion.py

 while True: 
            self._check_events() 
            self.ship.update() 
            self._update_bullets() 
            self._update_aliens() 
            self._update_screen() 

新建一个名为_update_aliens() 的方法管理外星人群的移动,更新子弹后再更新外星人的位置,检查是否有子弹击中了外星人。

alien_invasion.py

def _update_aliens(self): 
        """更新外星人群中所有外星人的位置。""" 
        self.aliens.update() 

对编组调用方法update() ,这将自动对每个外星人调用方法update() 。如果现 在运行这个游戏,你将看到外星人群向右移动,并在屏幕右边缘消失。

1.3.2创建表示外星人移动方向的设置

让外星人撞到屏幕右边缘后向下移动、再向左移动.

settings.py

          # 外星人设置 
         self.alien_speed = 1.0 
         self.fleet_drop_speed = 10 
         # fleet_direction为1表示向右移,为-1表示向左移。 
         self.fleet_direction = 1

设置fleet_drop_speed 指定有外星人撞到屏幕边缘时,外星人群向下移动的速度。设置fleet_direction ,们使用值1和-1来表示,并在外星人群改变方向时在这两个值之间切换。 (向右移时需要增大每个外星人的坐标,而向左移时需要减小每个外星人的坐 标。)

1.3.3检查外星人是否撞到了屏幕边缘

检查外星人是否撞到了屏幕边缘,还需修改update() 让 每个外星人都沿正确的方向移动。

  def check_edges(self): 
          """如果外星人位于屏幕边缘,就返回True。""" 
          screen_rect = self.screen.get_rect() 


         if self.rect.right >= screen_rect.right or self.rect.left <= 0: #1
                return True 
      def update(self): 
          """向左或向右移动外星人。""" 
         self.x += (self.settings.alien_speed *                          #2
                          self.settings.fleet_direction) 
          self.rect.x = self.x

对任意外星人调用新方法check_edges() ,看其是否位于屏幕左边缘或右边缘。如果外星人的rect 的属性right 大于或等于屏幕的rect 的right 属性,就说明外星人位于屏幕右边缘;如果外星人的rect 的left 属性小于或等于0,就说 明外星人位于屏幕左边缘(#1)

我们修改方法update() ,将移动量设置为外星人速度和fleet_direction 的乘 积,让外星人向左或向右移动(#2)。如果fleet_direction 为1,就将外星人 的当前 坐标增大alien_speed ,从而将外星人向右移;如果 fleet_direction 为-1,就将外星人的当前 坐标减去alien_speed ,从而将 外星人向左移。

1.3.4向下移动外星人群并改变移动方向

有外星人到达屏幕边缘时,需要将整群外行星下移,并改变它们的移动方向。为 此,需要在AlienInvasion 中添加一些代码,因为要在这里检查是否有外星人到达了左边缘或右边缘。

alien_invasion.py

    def _check_fleet_edges(self):
        """有外星人到达边缘时采取相应的措施。""" 
        for alien in self.aliens.sprites():                    #1
            if alien.check_edges():
                self._check_fleet_direction()                  #2
                break
    def _check_fleet_direction(self):
        """如果整个外星人群到达屏幕边缘,就改变它们的方向。"""
        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() (#1)。如果check_edges() 返回True ,就表明相应的外 星人位于屏幕边缘,需要改变外星人群的方向,因此调用 _change_fleet_direction() 并退出循环(#2)。在 _change_fleet_direction() 中,遍历所有外星人,将每个外星人下移设置 fleet_drop_speed 的值(#3)。然后,将fleet_direction 的值改为其当 前值与-1的乘积。调整外星人群移动方向的代码行没有包含在for 循环中,因为我 们要调整每个外星人的垂直位置,但只想调整外星人群移动方向一次。

alien_invasion.py

 def _update_aliens(self): 
        """ 
        检查是否有外星人位于屏幕边缘, 
        并更新整群外星人的位置。 
        """ 
        self._check_fleet_edges() 
        self.aliens.update()

1.4射杀外星人

创建了飞船和外星人群,但子弹击中外星人时将穿过外星人,因为还没有检查碰撞。在游戏编程中, 碰撞指的是游戏元素重叠在一起。要让子弹能够击落外星人,我们将使用sprite.groupcollide() 检测两个编组的成员之间的碰撞。

1.4.1检测子弹与外星人的碰撞

子弹击中外星人时,我们需要马上知道,以便碰撞发生后让子弹立即消失。为此, 我们将在更新子弹的位置后立即检测碰撞。 函数sprite.groupcollide() 将一个编组中每个元素的rect 同另一个编组中 每个元素的rect 进行比较。在这里,是将每颗子弹的rect 同每个外星人的rect 进行比较,并返回一个字典,其中包含发生了碰撞的子弹和外星人。在这个字典 中,每个键都是一颗子弹,而关联的值是被该子弹击中的外星人

在方法_update_bullets() 末尾,添加如下检查子弹和外星人碰撞的代码:

alien_invasion.py

  def _update_bullets(self): 
        """更新子弹的位置,并删除消失的子弹。""" 
        --snip-- 
        # 检查是否有子弹击中了外星人。
        # 如果是,就删除相应的子弹和外星人。 
        collisions = pygame.sprite.groupcollide( 
                self.bullets, self.aliens, True, True) 

将self.bullets 中所有的子弹都与self.aliens 中所有的外星 人进行比较,看它们是否重叠在一起。

每当有子弹和外星人的rect 重叠时, groupcollide() 就在它返回的字典中添加一个键值对。两个实参True 让Pygame 删除发生碰撞的子弹和外星人。(要模拟能够飞行到屏幕顶端、消灭击中的每个外星人的高能子弹,可将第一个布尔实参设置为False ,并保留第二个布尔参数为 True 。这样被击中的外星人将消失,但所有的子弹都始终有效,直到抵达屏幕顶端后消失。

1.4.2为测试创建大子弹、

测试有些功能时,可以修改游戏的某些设置,以便能够专注于游戏的特定方面。

威力超强的子弹让游戏的有些方法测试起来更容易。

1.4.3生成新的外星人群

要在一群外星人被消灭后再显示一群外星人,首先需要检查编组aliens是否为空。如果是,就调用_create_fleet() 。我们将在_update_bullets() 末尾执行这项任务,因为外星人都是在这里被消灭的: alien_invasion.py

     def _update_bullets(self): 
          --snip-- 

         if not self.aliens:                     #1
             # 删除现有的子弹并新建一群外星人。 
             self.bullets.empty()                #2
             self._create_fleet()            

(#1)处,检查编组aliens 是否为空。空编组相当于False ,因此这是一种检查编组是否为空的简单方式。如果编组aliens 为空,就使用方法empty() 删除编组中余下的所有精灵,从而删除现有的所有子弹#2)。我们还调用了 _create_fleet() ,在屏幕上重新显示一群外星人。

1.4.4提高子弹的速度

修改子弹的速度,可调整settings.py中bullet_speed 的值。

settings.py

         #子弹设置 
         self.bullet_speed = 1.5 
         self.bullet_width = 3 
         --snip-- 
 1.4.5重构 _update_bullets()
    def _update_bullets(self):
        """更新子弹的位置并删除消失的子弹。"""
        # 更新子弹的位置。
        self.bullets.update()
        # 删除消失的子弹。
        for bullet in self.bullets.copy():
            if bullet.rect.bottom <= 0:
                self.bullets.remove(bullet)
        self._check_bullet_alien_collisions()

    def _check_bullet_alien_collisions(self):
        # 检查是否有子弹击中了外星人。
        # 如果是,就删除子弹和外星人。
        collisions = pygame.sprite.groupcollide(
            self.bullets, self.aliens, True, True)
        if not self.aliens:
            # 删除现有的子弹并创建一个新的外星人群。
            self.bullets.empty()
            self._create_fleet()

1.5结束游戏

如果玩家没能在足够短的 时间内将整群外星人消灭干净,导致有外星人撞到了飞船或抵达屏幕底端,飞船将 被摧毁。与此同时,限制玩家可使用的飞船数,在玩家用光所有的飞船后,游戏将 结束。

1.5.1检测外星人和飞船碰撞

首先检查外星人和飞船之间的碰撞,以便在外星人撞上飞船时做出合适的响应。为 此,在AlienInvasion 中更新每个外星人的位置后,立即检测外星人和飞船之间的碰撞: alien_invasion.py

    def _update_aliens(self):
        """检查是否有外星人到达屏幕边缘,
        并更新外星人群中所有外星人的位置。"""
        self._check_fleet_edges()
        self.aliens.update()
        if pygame.sprite.spritecollideany(self.ship, self.aliens):  #1
            print("Ship hit!!!")                                    #2

函数spritecollideany() 接受两个实参:一个精灵和一个编组。它检查编组是 否有成员与精灵发生了碰撞,并在找到与精灵发生碰撞的成员后停止遍历编组。在这里,它遍历编组aliens ,并返回找到的第一个与飞船发生碰撞的外星人。 如果没有发生碰撞,spritecollideany() 将返回None ,因此(#1)处的if 代码块 不会执行。

如果找到了与飞船发生碰撞的外星人,它就返回这个外星人,因此if 代 码块将执行:打印“Ship hit!!!”(#2)。有外星人撞到飞船时,需要执行很多 任务:删除余下的外星人和子弹,让飞船重新居中,以及创建一群新的外星人。编 写完成这些任务的代码之前,需要确定检测外星人和飞船碰撞的方法是否可行。为此,最简单的方式就是调用函数print() 。

1.5.2响应外星人和飞船碰撞

不销毁Ship 实例并创建新的,而是通过跟踪游戏的统计信息来记录飞船被撞了多少次.

编写一个用于跟踪游戏统计信息的新类GameStats ,并将其保存为文件

game_stats.py:

class GameStats:
    """跟踪游戏的统计信息。"""
    def __init__(self):
        """初始化统计信息。"""
        self.settings = Settings()
        self.reset_stats()
    def reset_stats(self):
        """初始化在游戏运行期间可能变化的统计信息。"""
        self.ships_left = self.settings.ship_limit

settings.py

        # 飞船设置 
        self.ship_speed = 1.5 
        self.ship_limit = 3 

对alien_invasion.py做些修改,以创建一个GameStats 实例。更新这个文件开头的import 语句: alien_invasion.py

import sys 
from time import sleep 
import pygame 
from settings import Settings 
from game_stats import GameStats 
from ship i

从Python标准库的模块time 中导入函数sleep() ,以便在飞船被外星人撞到后让 游戏暂停片刻。我们还导入了GameStats 。

 def __init__(self): 
        --snip-- 
        self.screen = pygame.display.set_mode( 
            (self.settings.screen_width, self.settings.screen_height)) 
        pygame.display.set_caption("Alien Invasion") 
 
        # 创建一个用于存储游戏统计信息的实例。 
        self.stats = GameStats(self) 
 
        self.ship = Ship(self) 
        --snip-- 

在创建游戏窗口后、定义诸如飞船等其他游戏元素前,创建一个GameStats 实例。

有外星人撞到飞船时,将余下的飞船数减1,创建一群新的外星人,并将飞船重新放到屏幕底端的中央。另外,让游戏暂停片刻,让玩家在新外星人群出现前注意到发 生了碰撞并将重新创建外星人群。

将实现这些功能的大部分代码放到新方法_ship_hit() 中。在 _update_aliens() 中,将在有外星人撞到飞船时调用这个方法:

alien_invasion.py

    def _ship_hit(self):
        """响应被外星人撞到的飞船。"""
        # 将ship_left减1。
        self.stats.ships_left-=1                         #1
        
        # 清空余下的外星人和子弹。
        self.aliens.empty()                              #2
        self.bullets.empty()
        
        # 创建一群新的外星人,并将飞船放到屏幕底端中央。     
        self._create_fleet()                             #3
        self.ship.center_ship()
        
        # 暂停游戏。
        sleep(0.5)                                       #4

方法_ship_hit() 在飞船被外星人撞到时做出响应。在这个方法中,将余下的 飞船数减1(#1),再清空编组aliens 和bullets (#2)

接下来,创建一群新的外星人,并将飞船居中(#3)。(稍后将在Ship 类中添加 方法center_ship() 。)最后,在更新所有元素后(但在将修改显示到屏幕前) 暂停,让玩家知道飞船被撞到了(#3)。这里的函数调用sleep() 让游戏暂停半秒钟,让玩家能够看到外星人撞到了飞船。函数sleep() 执行完毕后,将接着执行 方法_update_screen() ,将新的外星人群绘制到屏幕上。

在_update_aliens() 中,当有外星人撞到飞船时,不调用函数print() ,而调 用_ship_hit() :

alien_invasion.py

 def _update_aliens(self): 
        --snip-- 
        if pygame.sprite.spritecollideany(self.ship, self.aliens): 
            self._ship_hit()
1.5.3 有外星人到达屏幕底端

如果有外星人到达屏幕底端,我们将像有外星人撞到飞船那样做出响应。为检测这 种情况,在alien_invasion.py中添加一个新方法:

alien_invasion.py

    def _check_alien_bottom(self):
        """检查是否有外星人到达了屏幕底端。"""
        screen.rect=self.screen.get_rect()
        for alien in self.aliens.sprites():
            if alien.rect.bottom >= screen.rect.bottom:     #1
                #像飞船被撞到一样处理。
                self._ship_hit()
                break

方法_check_aliens_bottom() 检查是否有外星人到达了屏幕底端。到达屏幕底端后,外星人的属性rect.bottom 大于或等于屏幕的属性rect.bottom (#1)。如果有外星人到达屏幕底端,就调用_ship_hit() 。只要检测到一个外星 人到达屏幕底端,就无须检查其他外星人了,因此在调用_ship_hit() 后退出循环。

我们在_update_aliens() 中调用_check_aliens_bottom() :

alien_invasion.py

 def _update_aliens(self): 
        --snip-- 
        # 检查是否有外星人撞到飞船。 
        if pygame.sprite.spritecollideany(self.ship, self.aliens): 
            self._ship_hit() 
        # 检查是否有外星人到达了屏幕底端。 
        self._check_aliens_bottom()

在更新所有外星人的位置并检测是否有外星人和飞船发生碰撞后调用 _check_aliens_bottom() 。

1.5.4游戏结束

现在这个游戏看起来更完整了,但它永远都不会结束,只是ships_left 不断变成 越来越小的负数。下面在GameStats 中添加一个作为标志的属性game_active ,以便在玩家的飞船用完后结束游戏。首先,在GameStats 类的方法 __init__() 末尾设置这个标志:

game_stats.py

def _ship_hit(self): 
        """响应飞船被外星人撞到。""" 
        if self.stats.ships_left > 0: 
            # 将ships_left减1。 
            self.stats.ships_left -= 1 
          --snip-- 
            # 暂停。 
            sleep(0.5) 
        else: 
            self.stats.game_active = False 

1.6确定应运行游戏的哪些部分

确定游戏的哪些部分在任何情况下都应运行,哪些部分仅在游戏处于活动 状态时才运行:

alien_invasion.py

   def run_game(self): 
        """开始游戏主循环。""" 
        while True: 
            self._check_events() 
            if self.stats.game_active: 
                self.ship.update() 
                self._update_bullets() 
                self._update_aliens() 
            self._update_screen() 


http://www.kler.cn/a/585243.html

相关文章:

  • 12 DHCP的内容和HTTP的改良
  • 车载以太网测试-11【网络层-ICMP协议】
  • 02-Canvas-fabric.BaseBrush绘图工具
  • 通信协议传输过程中的序列化和反序列化机制
  • 2025-03-14 学习记录--C/C++-PTA 习题2-1 求整数均值
  • AI时代下的心理咨询师新利器:心理咨询小程序
  • 蓝桥杯十天冲刺(C++)-输入输出
  • 使用ZYNQ芯片和LVGL框架实现用户高刷新UI设计系列教程(第三讲)
  • 苍穹外卖实战附源码-DAY1
  • 优选算法的匠心之艺:二分查找专题(一)
  • 微前端解决方案之MicroApp
  • 基于YOLO11深度学习的舌苔舌象检测识别与诊断系统【python源码+Pyqt5界面+数据集+训练代码】
  • OpenCV特征提取与深度学习CNN特征提取差异
  • 58.Harmonyos NEXT 图片预览组件架构设计与实现原理
  • 【Idea】 xml 文本粘贴保持原有文本的缩进格式
  • C语言的机器学习
  • C++ STL 深度解析:vector 的全面指南与进阶技巧
  • Java 实现定长报文模拟器(支持配置文件 默认值)
  • 计算机网络TCP/IP四层模型
  • 列表动态列处理