title: Python Crash Course -Alien Invasion -Game Ending Error
body: <p>I am working on the Alien Invasion project at the end of Python Crash Course 2nd Edition and I am having a problem with my game ending after the user runs out of lives. The game is supposed to end after all 3 lives are lost but when that happens for mine the aliens continue to move off the bottom of the screen. There are no error messages and from my many checks through the code I have entered it word for word from the book. I have worked up to the section where the scoreboard is added but now I am resetting the scoreboard which requires the game to end properly. Below is a copy of all the necessary code files that would apply to this issue. Each separate file is indicated by #filename.py and the code for said file follows. If there is anything else needed to check through this please let me know.</p>
  <pre><code># Project Qapla'
  # Matthew Moore
  # alien_invasion.py
  
  import sys
  from time import sleep
  
  import pygame
  
  from settings import Settings
  from game_stats import GameStats
  from scoreboard import Scoreboard
  from button import Button
  from ship import Ship
  from bullet import Bullet
  from alien import Alien
  
  class AlienInvasion:
         &quot;&quot;&quot;Overall class to manage assets and behaviour.&quot;&quot;&quot;
         
         def __init__(self):
             &quot;&quot;&quot;Initialize the game, and create game resources.&quot;&quot;&quot;
             pygame.init()
             self.settings = Settings()
             
             #Partial screen play control
             self.screen = pygame.display.set_mode(
                 (self.settings.screen_width,self.settings.screen_height))           
             
             #Full screen play control
             #self.screen = pygame.display.set_mode((0,0), pygame.FULLSCREEN)
             #self.settings.screen_width = self.screen.get_rect().width
             #self.settings.screen_height = self.screen.get_rect().height
                         
             pygame.display.set_caption(&quot;Alien Invasion&quot;)
             self.stats = GameStats(self)   
             self.sb = Scoreboard(self) 
             self.ship = Ship(self)
             self.bullets = pygame.sprite.Group()
             self.aliens = pygame.sprite.Group()
             
             self._create_fleet()
             
             #Make the play button
             self.play_button = Button(self, &quot;Play&quot;)
             
             
             
         def run_game(self):
             &quot;&quot;&quot;Start the main loop for the game.&quot;&quot;&quot;
             while True:
                 self._check_events()
                 
                 if self.stats.game_active:
                     self.ship.update()
                     self._update_bullets()
                     self._update_aliens()
                 
                 self._update_screen()
                 
                             
                 #Make the most recently drawn screen visible.
                 pygame.display.flip()
   
  
         def _check_events(self):
             &quot;&quot;&quot;Respond to keypresses abd mouse events.&quot;&quot;&quot;
             for event in pygame.event.get():
                 if event.type == pygame.QUIT:
                     sys.exit()
                 elif event.type == pygame.KEYDOWN:
                     self._check_keydown_events(event)
                 elif event.type == pygame.KEYUP:
                     self._check_keyup_events(event)
                 elif event.type == pygame.MOUSEBUTTONDOWN:
                     mouse_pos = pygame.mouse.get_pos()
                     self._check_play_button(mouse_pos)
  
  
         def _check_keydown_events(self,event):
             &quot;&quot;&quot;Respond to key presses.&quot;&quot;&quot;       
             if event.key == pygame.K_RIGHT:
                 self.ship.moving_right = True
             elif event.key == pygame.K_LEFT:
                 self.ship.moving_left = True
             elif event.key == pygame.K_q:
                 sys.exit()
             elif event.key == pygame.K_SPACE:
                 self._fire_bullet()
                  
  
         def _check_keyup_events(self,event):
             &quot;&quot;&quot;Respond to key releases.&quot;&quot;&quot;      
             if event.key == pygame.K_RIGHT:
                 self.ship.moving_right = False
             elif event.key == pygame.K_LEFT:
                 self.ship.moving_left = False
                 
         def _check_play_button(self, mouse_pos):
             &quot;&quot;&quot;Starts new game when player clicks play button&quot;&quot;&quot;
             button_clicked = self.play_button.rect.collidepoint(mouse_pos)
             if button_clicked and not self.stats.game_active:
                 #Reset the game statistics
                 self.settings.initialize_dynamic_settings()
                 self.stats.game_active = True
                 
                 #Get rid of any remaining aliens and bullets.
                 self.aliens.empty()
                 self.bullets.empty()
                 
                 #create a new fleet and center the ship
                 self._create_fleet()
                 self.ship.center_ship()
                 
                 #Hide Mouse cursor
                 pygame.mouse.set_visible(False)
  
         def _fire_bullet(self):
             &quot;&quot;&quot;Create a new bullet and add it to the bullets group.&quot;&quot;&quot;
             if len(self.bullets) &lt; self.settings.bullets_allowed:
                 new_bullet = Bullet(self)
                 self.bullets.add(new_bullet)
              
         def _update_bullets(self):
             &quot;&quot;&quot;Update postiion of bullets and get rid of old bullets.&quot;&quot;&quot;
             #Update bullet positions
             self.bullets.update()
             
             #Get rid of bullets that have disappeared
             for bullet in self.bullets.copy():
                 if bullet.rect.bottom &lt;= 0:
                     self.bullets.remove(bullet)
                 #print(len(self.bullets))
             
             self._check_bullet_alien_collision()
         
         def _check_bullet_alien_collision(self):
             &quot;&quot;&quot;Responds to bullet-alien collisions&quot;&quot;&quot;
             #Check for any bullets that have hit aliens
             #If so, get rid of alien and bullet
             collisions = pygame.sprite.groupcollide(
                 self.bullets, self.aliens, True, True)
                 
             if collisions:
                 self.stats.score += self.settings.alien_points
                 self.sb.prep_score()
                 
             if not self.aliens:
                 #Destroy existing bullets and create a new fleet
                 self.bullets.empty()
                 self._create_fleet()
                 self.settings.increase_speed()
         
         def _update_aliens(self):
             &quot;&quot;&quot;Update the positions of all alliens in the fleet/Check if
             fleet is on an edge&quot;&quot;&quot;
             self._check_fleet_edges()
             self.aliens.update()
             
             #look for alien-ship collisions
             if pygame.sprite.spritecollideany(self.ship, self.aliens):
                 self._ship_hit()
                 
             self._check_alien_bottom()
                 
         def _ship_hit(self):
             &quot;&quot;&quot;Responds to a ship being hit by an alien&quot;&quot;&quot;
             if self.stats.ships_left &gt; 0:
                 self.stats.ships_left -= 1
                 self.aliens.empty()
                 self.bullets.empty()
                 self._create_fleet()
                 self.ship.center_ship()
                 sleep(0.5)
             else:
                 self.stats.game_active_ = False
                 pygame.mouse.set_visible(True)
                 
         def _create_fleet(self):
             &quot;&quot;&quot;create the fleet of aliens&quot;&quot;&quot;
             #create an alien and find the number of aliens in a row.
             #Spacing between each alien is equal to one alien width.
             alien = Alien(self)
             alien_width, alien_height = alien.rect.size
             avaliable_space_x = self.settings.screen_width - (2 * alien_width)
             number_aliens_x = avaliable_space_x // (2*alien_width)
             
             #determine th enumber of rows of aliens that fit on the screen
             ship_height = self.ship.rect.height
             avaliable_space_y = (self.settings.screen_height-
                                     (3*alien_height) - ship_height)
             number_rows = avaliable_space_y // (2 * alien_height)
             
             #Create the full fleet of aliens
             for row_number in range(number_rows):
                 for alien_number in range(number_aliens_x):
                     self._create_alien(alien_number, row_number)
                 
         def _create_alien(self, alien_number, row_number):
             #create an alien and [place it in the row
             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_height + 2 * alien.rect.height * row_number
             self.aliens.add(alien)
          
         def _check_fleet_edges(self):
             &quot;&quot;&quot;Respond approprietly if any aliens have touched an edge&quot;&quot;&quot;
             for alien in self.aliens.sprites():
                 if alien.check_edges():
                     self._change_fleet_direction()
                     break
                     
         def _check_alien_bottom(self):
             &quot;&quot;&quot;Checks if aliens have reached the bottom of the screen&quot;&quot;&quot;
             screen_rect = self.screen.get_rect()
             for alien in self.aliens.sprites():
                 if alien.rect.bottom &gt;= screen_rect.bottom:
                     self._ship_hit()
                     break
                     #treats it the same as ship getting hit
                     
         def _change_fleet_direction(self):
             &quot;&quot;&quot;Drop the fleet and change direction&quot;&quot;&quot;
             for alien in self.aliens.sprites():
                 alien.rect.y += self.settings.fleet_drop_speed
             self.settings.fleet_direction *= -1
         
         def _update_screen(self):
             &quot;&quot;&quot;Update images on the screen, and flip to the new screen.&quot;&quot;&quot;
             # Redraw the screen during each pass
             self.screen.fill(self.settings.bg_color)
             self.ship.blitme()
             for bullet in self.bullets.sprites():
                 bullet.draw_bullet() 
             self.aliens.draw(self.screen)
             #Draw the score information
             self.sb.show_score()
             #draw the button if game is inactive
             if not self.stats.game_active:
                 self.play_button.draw_button()
             
             pygame.display.flip()
              
                         
  if __name__ == '__main__':
      # Make a game instance, and run the game.
      ai = AlienInvasion()
      ai.run_game()
  
  #alien.py
  import pygame
  from pygame.sprite import Sprite
  
  class Alien(Sprite):
      &quot;&quot;&quot;A class to represent a single alien in the fleet&quot;&quot;&quot;
      
      def __init__(self, ai_game):
          &quot;&quot;&quot;Initialize the alien and its starting position&quot;&quot;&quot;
          super().__init__()
          self.screen = ai_game.screen
          self.settings = ai_game.settings
          
          #Load the alien image and set its rect attribute
          self.image = pygame.image.load('images/alien.bmp')
          self.rect = self.image.get_rect()
          
          #Start each new alien near the top left of the screen
          self.rect.x = self.rect.width
          self.rect.y = self.rect.height
          
          #store the aliens exact horizontal position
          self.x = float(self.rect.x)
          
      def update(self):
          &quot;&quot;&quot;Move alien to the right or left&quot;&quot;&quot;
          self.x += (self.settings.alien_speed * self.settings.fleet_direction)
          self.rect.x = self.x
      
      def check_edges(self):
          &quot;&quot;&quot;Returns true if alien is at edge of the screen&quot;&quot;&quot;
          screen_rect = self.screen.get_rect()
          if self.rect.right &gt;= screen_rect.right or self.rect.left &lt;= 0:
              return True
  
  # settings.py
  
  class Settings:
      &quot;&quot;&quot;A class to store all settings for Alien Invasion.&quot;&quot;&quot;
      
      def __init__(self):
          &quot;&quot;&quot;Initialize the game's static settings.&quot;&quot;&quot;
          
          # Screen settings
          self.screen_width = 1200
          self.screen_height = 800
          self.bg_color = (230, 230, 230)
          
          #Ship settings
          self.ship_speed = 3
          self.ship_limit = 3
          
          #Bullet settings
          self.bullet_speed = 2.0
          self.bullet_width = 3
          self.bullet_height = 15
          self.bullet_color = (60, 60, 60)
          self.bullets_allowed = 3
          
          #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
          
          #How quickly the game speeds up
          self.speedup_scale = 1.1
          
          self.initialize_dynamic_settings()
      
      def initialize_dynamic_settings(self):
          &quot;&quot;&quot;Initialize settings that change throughout the game&quot;&quot;&quot;
          self.ship_speed = 1.5
          self.bullet_speed = 3.0
          self.alien_speed = 1.0
          
          self.fleet_direction = 1
          
          #Scoring
          self.alien_points = 50
      
      def increase_speed(self):
          &quot;&quot;&quot;Increases speed settings&quot;&quot;&quot;
          self.ship_speed *= self.speedup_scale
          self.bullet_speed *= self.speedup_scale
          self.alien_speed *= self.speedup_scale
  
  #game_stats.py
  
  class GameStats:
      &quot;&quot;&quot;Track statistics of alien invasion&quot;&quot;&quot;
      def __init__(self, ai_game):
          &quot;&quot;&quot;Initialize stats&quot;&quot;&quot;
          self.settings = ai_game.settings
          self.reset_stats()
          self.game_active = False
          
      def reset_stats(self):
          &quot;&quot;&quot;Initialize stats that can change during the game&quot;&quot;&quot;
          self.ships_left = self.settings.ship_limit
          self.score = 0
  
  #ship.py
  
  import pygame
  
  class Ship:
      &quot;&quot;&quot;A class to manage the ship.&quot;&quot;&quot;
      
      def __init__(self, ai_game):
          &quot;&quot;&quot;Initiatilize the ship and set its starting position.&quot;&quot;&quot;
          self.screen = ai_game.screen
          self.settings = ai_game.settings
          self.screen_rect = ai_game.screen.get_rect()
          
          # Load the ship image and get its rect.
          self.image = pygame.image.load('images/ship.bmp')
          self.rect = self.image.get_rect()
          
          #Start each new ship at the bottom center of the screen.
          self.rect.midbottom = self.screen_rect.midbottom
          
          #Store a decimal value for the ships horizontal position.
          self.x = float(self.rect.x)
          
          #Movement flag
          self.moving_right = False
          self.moving_left = False
          
  
          
      def update(self):
          &quot;&quot;&quot;Update the ship's position based on the movement flags.&quot;&quot;&quot;
          #Update the ships x value, not th erect.
          if self.moving_right and self.rect.right &lt; self.screen_rect.right:
              self.x += self.settings.ship_speed
          if self.moving_left and self.rect.left &gt; 0:
              self.x -= self.settings.ship_speed
          
          #Update rect object from self.x.
          self.rect.x = self.x
  
      
      def blitme(self):
          &quot;&quot;&quot;&quot;Draw the ship at its current location.&quot;&quot;&quot;
          self.screen.blit(self.image, self.rect)
          
      def center_ship(self):
          self.rect.midbottom = self.screen_rect.midbottom
          self.x = float(self.rect.x)
  </code></pre>