class AlienInvasion: """Overall class used to manage game assets and behaviour.""" def __init__(self): """Initialise the game, and create game resources.""" pygame.init() self.settings = Settings() self.finder = DataFileFinder() # Uncomment code to run Alien Invasion in full screen mode. # 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 # Comment line out when trying to run Alien Invasion in full screen # mode. self.screen = pygame.display.set_mode( (self.settings.screen_width, self.settings.screen_height)) pygame.display.set_caption("Alien Invasion") # Create an instance to store game statistics, and create a scoreboard. self.stats = GameStats(self) self.sb = Scoreboard(self) self.spaceship = Spaceship(self) self.bullets = pygame.sprite.Group() self.aliens = pygame.sprite.Group() self._create_wave() # Create game title. self.title = GameTitle(self) # Create help text. self.help = Help(self) # Make buttons. self.play_button = Button( self, pygame.image.load( self.finder.find_data_file('play_button.bmp', 'images'))) self.help_button = Button( self, pygame.image.load( self.finder.find_data_file('help_button.bmp', 'images'))) self.exit_button = Button( self, pygame.image.load( self.finder.find_data_file('exit_button.bmp', 'images'))) self.resume_button = Button( self, pygame.image.load( self.finder.find_data_file('resume_button.bmp', 'images'))) self.quit_button = Button( self, pygame.image.load( self.finder.find_data_file('quit_button.bmp', 'images'))) self.back_button = Button( self, pygame.image.load( self.finder.find_data_file('back_button.bmp', 'images'))) self.ok_button = Button( self, pygame.image.load( self.finder.find_data_file('ok_button.bmp', 'images'))) # Give spacing between buttons. self.help_button.rect.y += self.help_button.rect.height + 20 self.exit_button.rect.y += (self.exit_button.rect.height + 20) * 2 self.quit_button.rect.y += self.quit_button.rect.height + 20 self.back_button.rect.y = (self.help.how_to_text_rects[-1].bottom + 50) self.ok_button.rect.y = self.screen.get_rect().bottom - 250 # Create texts used in the game. self.get_ready_text = Text(self, 'Get Ready...', 24) self.get_ready_text.text_rect.y -= 48 self.incoming_wave_text = Text(self, 'Incoming Wave...', 36) def run_game(self): """Start the main loop for the game.""" while True: self._check_events() self._check_timer() if (self.stats.game_active and not self.stats.game_paused and not self.stats.help_active and not self.stats.game_over): self.spaceship.update() self._update_bullets() # Make sure aliens aren't updated when prep text is being shown # to the user. if not self.stats.get_ready and not self.stats.incoming_wave: self._update_aliens() self._update_screen() def _check_events(self): # Repspond to keyboard and mouse events. 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.MOUSEBUTTONUP: mouse_pos = pygame.mouse.get_pos() self._check_play_button(mouse_pos) self._check_help_button(mouse_pos) self._check_exit_button(mouse_pos) self._check_resume_button(mouse_pos) self._check_quit_button(mouse_pos) self._check_back_button(mouse_pos) self._check_ok_button(mouse_pos) def _check_play_button(self, mouse_pos): """Start a new game when the player clicks Play.""" button_clicked = self.play_button.rect.collidepoint(mouse_pos) if (button_clicked and not self.stats.game_active and not self.stats.game_paused and not self.stats.help_active and not self.stats.game_over): # Reset the game settings. self.settings.initialise_dynamic_settings # Reset game statistics. self.stats.reset_stats() self.stats.game_active = True self.sb.prep_score() self.sb.prep_wave() self.sb.prep_spaceships() # Get rid of any remaining aliens and bullets. self.aliens.empty() self.bullets.empty() # Create a new wave and center the spaceship. self._create_wave() self.spaceship.center_spaceship() # Hide the mouse cursor. pygame.mouse.set_visible(False) # Show get ready text. self.stats.get_ready = True self._check_get_ready_counter() def _check_help_button(self, mouse_pos): """Show help text when the player clicks Help.""" button_clicked = self.help_button.rect.collidepoint(mouse_pos) if (button_clicked and not self.stats.game_active and not self.stats.game_paused and not self.stats.help_active and not self.stats.game_over): self.stats.help_active = True def _check_exit_button(self, mouse_pos): """Exit game when the player clicks Exit.""" button_clicked = self.exit_button.rect.collidepoint(mouse_pos) if (button_clicked and not self.stats.game_active and not self.stats.game_paused and not self.stats.help_active and not self.stats.game_over): # Exit the game. sys.exit() def _check_resume_button(self, mouse_pos): """Resume current game when the player clicks Resume.""" button_clicked = self.resume_button.rect.collidepoint(mouse_pos) if (button_clicked and self.stats.game_active and self.stats.game_paused and not self.stats.help_active and not self.stats.game_over): if hasattr(self, 'timer'): if (self.timer != None and not self.timer.active): self.timer.resume() self.stats.game_paused = False # Hide the mouse cursor. pygame.mouse.set_visible(False) def _check_quit_button(self, mouse_pos): """Go back to main menu when the player clicks Quit.""" button_clicked = self.quit_button.rect.collidepoint(mouse_pos) if (button_clicked and self.stats.game_active and self.stats.game_paused and not self.stats.help_active and not self.stats.game_over): self.stats.game_active = False self.stats.game_paused = False self.stats.help_active = False def _check_back_button(self, mouse_pos): """Go back to main menu when the player clicks Back.""" button_clicked = self.back_button.rect.collidepoint(mouse_pos) if (button_clicked and not self.stats.game_active and not self.stats.game_paused and self.stats.help_active and not self.stats.game_over): self.stats.game_active = False self.stats.game_paused = False self.stats.help_active = False def _check_ok_button(self, mouse_pos): """Go back to main menu when the player clicks Ok.""" button_clicked = self.ok_button.rect.collidepoint(mouse_pos) game_over = (self.stats.game_active and not self.stats.game_paused and not self.stats.help_active and self.stats.game_over) if button_clicked and game_over: self.stats.game_active = False self.stats.game_paused = False self.stats.help_active = False self.stats.game_over = False def _check_keydown_events(self, event): """Respond to keypresses.""" if event.key == pygame.K_RIGHT: # Move the spaceship to the right. self.spaceship.moving_right = True elif event.key == pygame.K_LEFT: # Move the spaceship to the left. self.spaceship.moving_left = True elif event.key == pygame.K_q: sys.exit() elif (event.key == pygame.K_SPACE and self.stats.game_active and not self.stats.get_ready and not self.stats.incoming_wave): self._fire_bullet() elif event.key == pygame.K_p and self.stats.game_active: self.stats.game_paused = True # Show the mouse cursor. pygame.mouse.set_visible(True) def _check_keyup_events(self, event): """Respond to key releases.""" if event.key == pygame.K_RIGHT: self.spaceship.moving_right = False elif event.key == pygame.K_LEFT: self.spaceship.moving_left = False def _check_timer(self): """ Check whether there are any threads being used that need to be paused. """ if hasattr(self, 'timer'): if (self.timer != None and self.stats.game_paused and self.timer.active): self.timer.pause() def _create_wave(self): """Create the wave of aliens.""" # Create an alien and find the number of aliens in a row. # Determine equal spacing between all aliens in the row. alien = Alien(self) alien_width, alien_height = alien.rect.size available_space_x = self.settings.screen_width - (2 * alien_width) number_of_aliens_x = available_space_x // (2 * alien_width) alien_spacing_x = (number_of_aliens_x * alien_width) // (number_of_aliens_x - 1) # Determine the number of rows of aliens that fit on the screen. spaceship_height = self.spaceship.rect.height avialable_space_y = self.settings.screen_height - ( (5 * alien_height) + spaceship_height) number_of_rows = avialable_space_y // (2 * alien_height) # Create the full wave of aliens. for row_number in range(number_of_rows): for alien_number in range(number_of_aliens_x): self._create_alien(alien_number, alien_spacing_x, row_number) def _create_alien(self, alien_number, alien_spacing_x, 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 + ( (alien_width + alien_spacing_x) * alien_number) alien.rect.x = alien.x alien.rect.y = alien_height + 50 + (2 * alien_height * row_number) self.aliens.add(alien) def _check_wave_edges(self): """Respond appropriately if any aliens have reached the edge.""" for alien in self.aliens.sprites(): if alien.check_edges(): self._change_wave_direction() break def _change_wave_direction(self): """Drop the entire wave and change the wave's direction.""" for alien in self.aliens.sprites(): alien.rect.y += self.settings.wave_drop_speed self.settings.wave_direction *= -1 def _fire_bullet(self): """Create a new bullet and add it to the bullets group.""" if len(self.bullets) < self.settings.bullets_allowed: new_bullet = Bullet(self) self.bullets.add(new_bullet) self.stats.bullets_fired += 1 def _update_bullets(self): """Update position of bullets and get rid of old bullets.""" # Update bullet positons. self.bullets.update() # Get rid of bullets that have disappeared. 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): """Respond to bullet-alien collisions.""" # Remove any bullets and aliens that have collided. collisions = pygame.sprite.groupcollide(self.bullets, self.aliens, True, True) if collisions: for aliens in collisions.values(): self.stats.score += self.settings.alien_points * len(aliens) self.stats.aliens_destroyed += len(aliens) self.sb.prep_score() self.sb.check_high_score() if not self.aliens: # Destroy existing bullets and create new wave. self.bullets.empty() self.settings.increase_speed() # Increase wave. self._create_wave() self.stats.wave += 1 self.sb.prep_wave() # Pause to allow player to get ready. self.stats.incoming_wave = True # Create timer to use when waiting for incoming wave of aliens. self.timer = ResumableTimer(1.0, self._incoming_wave) self.timer.start() def _spaceship_hit(self): """Respond to the spaceship being hit by an alien.""" if self.stats.spaceships_left > 0: # Decrement spaceships_left, and update scoreboard. self.stats.spaceships_left -= 1 self.sb.prep_spaceships() # Check to see if the has anymore spaceships left. if self.stats.spaceships_left <= 0: self.stats.game_over = True pygame.mouse.set_visible(True) return # Get rid of any remaining aliens and bullets. self.aliens.empty() self.bullets.empty() # Create wave of aliens and center the spaceship. self._create_wave() self.spaceship.center_spaceship() # Create timer to use when waiting for incoming wave of aliens. self.stats.get_ready = True self._check_get_ready_counter() def _check_get_ready_counter(self): if self.stats.get_ready_counter > 0: self.stats.get_ready_counter -= 1 self.timer = ResumableTimer(1.0, self._check_get_ready_counter) self.timer.start() else: self.stats.get_ready = False self.stats.reset_counter() self.timer = None def _incoming_wave(self): self.stats.incoming_wave = False self.timer = None def _check_aliens_bottom(self): """Check if any aliens have reached the bottom of the screen.""" screen_rect = self.screen.get_rect() for alien in self.aliens.sprites(): if alien.rect.bottom >= screen_rect.bottom - 20: self._spaceship_hit() break def _update_aliens(self): """ Check if the wave is at an edge, then update the positions of all aliens in the wave. """ self._check_wave_edges() self.aliens.update() # Look for alien-ship collisions. if pygame.sprite.spritecollideany(self.spaceship, self.aliens): self._spaceship_hit() # Look for aliens hitting the bottom of the screen. self._check_aliens_bottom() def _update_screen(self): # Update images on the screen, and flip to the new screen. self.screen.fill(self.settings.bg_colour) # Draw the spaceship and the score information. if self.stats.game_active and not self.stats.game_over: self.spaceship.blitme() for bullet in self.bullets.sprites(): bullet.draw_bullet() # Draw the score information. self.sb.show_score() # Draw get ready text. if (self.stats.game_active and not self.stats.game_over and self.stats.get_ready and not self.stats.incoming_wave): self.get_ready_text.draw_text() # Create count to show on screen. count = str(self.stats.get_ready_counter + 1) self.counter_text = Text(self, count, 48) # Draw count. self.counter_text.draw_text() # Draw incoming wave text. if (self.stats.game_active and not self.stats.game_over and not self.stats.get_ready and self.stats.incoming_wave): self.incoming_wave_text.draw_text() # Draw aliens. if (self.stats.game_active and not self.stats.game_over and not self.stats.get_ready and not self.stats.incoming_wave): self.aliens.draw(self.screen) # Draw the play, help and quit button if the game is invactive. if (not self.stats.game_active and not self.stats.game_paused and not self.stats.help_active and not self.stats.game_over): self.title.draw_title() self.play_button.draw_button() self.help_button.draw_button() self.exit_button.draw_button() # Draw the resume and back button if the game is paused. if (self.stats.game_active and self.stats.game_paused and not self.stats.help_active and not self.stats.game_over): self.resume_button.draw_button() self.quit_button.draw_button() # Draw user game stats if the game is over. if (self.stats.game_active and not self.stats.game_paused and not self.stats.help_active and self.stats.game_over): self.stats.show_stats() self.ok_button.draw_button() # Draw the help text and button if the game is paused. if (not self.stats.game_active and not self.stats.game_paused and self.stats.help_active and not self.stats.game_over): self.help.show_help() self.back_button.draw_button() # Make the most recently drawn screen visible. pygame.display.flip()
class AlienInvasion(): '''Classe geral para gerir os componentes e o comportamento do jogo''' def __init__(self): """Inicializa o jogo e cria os recursos do mesmo""" pygame.init() self.settings = Settings() self.clock = pygame.time.Clock() # Carregando a janela do jogo self.screen = pygame.display.set_mode( (self.settings.width, self.settings.height)) pygame.display.set_caption('Alien Invasion') self.game_stats = GameStats(self) self.scoreboard = Scoreboard(self) self.easy_game_button = button.EasyModeButton(self, 'Easy') self.normal_game_button = button.NormalModeButton(self, 'Normal') self.hard_game_button = button.HardModeButton(self, 'Hard') self.spaceship = Spaceship(self) self.bullets = pygame.sprite.Group() self.aliens = pygame.sprite.Group() self._create_fleet() def _check_events(self): '''Responde aos inputs de mouse e teclado''' for event in pygame.event.get(): if event.type == pygame.QUIT: sys.exit() elif event.type == pygame.KEYDOWN: if event.key == pygame.K_SPACE: self._fire_bullet() elif event.type == pygame.MOUSEBUTTONDOWN: mouse_position = pygame.mouse.get_pos() self._check_easy_game_button(mouse_position) self._check_normal_game_button(mouse_position) self._check_hard_game_button(mouse_position) self.spaceship.update() def _check_easy_game_button(self, mouse_position): '''Começa um novo jogo quando o jogador clica em Start''' button_clicked = self.easy_game_button.rect.collidepoint( mouse_position) if button_clicked and not self.game_stats.game_playing: self._start_new_easy_mode_game() def _check_normal_game_button(self, mouse_position): '''Começa um novo jogo quando o jogador clica em Start''' button_clicked = self.normal_game_button.rect.collidepoint( mouse_position) if button_clicked and not self.game_stats.game_playing: self._start_new_normal_mode_game() def _check_hard_game_button(self, mouse_position): '''Começa um novo jogo quando o jogador clica em Start''' button_clicked = self.hard_game_button.rect.collidepoint( mouse_position) if button_clicked and not self.game_stats.game_playing: self._start_new_hard_mode_game() def _start_new_easy_mode_game(self): '''Cria um novo jogo destruindo os aliens e as balas restantes''' self.settings.easy_mode_dynamic_settings() self.game_stats.reset_stats() self.game_stats.game_playing = True self.scoreboard._score() self.scoreboard._wave() self.scoreboard._lives() self.aliens.empty() self.bullets.empty() self._create_fleet() self.spaceship.center_spaceship() pygame.mouse.set_visible(False) def _start_new_normal_mode_game(self): '''Cria um novo jogo destruindo os aliens e as balas restantes''' self.settings.normal_mode_dynamic_settings() self.game_stats.reset_stats() self.game_stats.game_playing = True self.scoreboard._score() self.scoreboard._wave() self.scoreboard._lives() self.aliens.empty() self.bullets.empty() self._create_fleet() self.spaceship.center_spaceship() pygame.mouse.set_visible(False) def _start_new_hard_mode_game(self): '''Cria um novo jogo destruindo os aliens e as balas restantes''' self.settings.hard_mode_dynamic_settings() self.game_stats.reset_stats() self.game_stats.game_playing = True self.scoreboard._score() self.scoreboard._wave() self.scoreboard._lives() self.aliens.empty() self.bullets.empty() self._create_fleet() self.spaceship.center_spaceship() pygame.mouse.set_visible(False) def _fire_bullet(self): '''Cria uma nova bala e a adiciona no grupo bullets se o número de balas na tela for menor que o permitido''' if len(self.bullets) < self.settings.bullet_allowed: new_bullet = Bullet(self) self.bullets.add(new_bullet) def _create_fleet(self): '''Cria uma frota de aliens''' # Cria um alien alien = Alien(self) # Acha o número de aliens que cabem numa linha # Pega a largura e a altura de um alien alien_width, alien_height = alien.rect.size # Calcula o espaço horizontal vazio space_x = self.settings.width - (2 * alien_width) # Calcula quantos aliens cabem nesse espaço vazio number_aliens_x = space_x // (2 * alien_width) # Determina o número de linhas que cabem na tela spaceship_height = self.spaceship.rect.height space_y = (self.settings.height - (3 * alien_height) - spaceship_height) number_rows = space_y // (4 * alien_height) # Cria uma frota de 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): '''Cria um alien e o coloca na linha''' alien = Alien(self) alien_width, alien_height = alien.rect.size # Define a coordenada x onde ele vai ser colocado alien.x = alien_width + 2 * alien_width * alien_number # Define a posição do rect alien.rect.x = alien.x alien.rect.y = alien.rect.height + 2 * alien_height * row_number # Adiciona o novo alien para o grupo aliens self.aliens.add(alien) def _check_fleet_edges(self): '''Responde de acordo se um alien encostar no limite''' for alien in self.aliens.sprites(): if alien.check_edges(): self._change_fleet_direction() break def _change_fleet_direction(self): '''Faz toda a frota descer e muda a direção da mesma''' for alien in self.aliens.sprites(): alien.rect.y += self.settings.fleet_drop_speed self.settings.fleet_direction *= -1 def _spaceship_hit(self): '''Ação que ocorre quando a nave é acertada por um alien''' # Diminui o número de vidas if self.game_stats.spaceship_lives > 0: self.game_stats.spaceship_lives -= 1 self.scoreboard._lives() # Destrói os aliens e as balas restantes self.aliens.empty() self.bullets.empty() # Cria uma nova frota self._create_fleet() # Centraliza a nave self.spaceship.center_spaceship() # Pausa sleep(0.5) else: self.game_stats.game_playing = False pygame.mouse.set_visible(True) def _update_bullets(self): '''Atualiza a posição das balas e exclui as que não aparecem mais na tela''' # Atualiza a posição das balas self.bullets.update() # Excluindo as balas que não estão mais aparecendo na tela 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): '''Colisão entre as balas e os aliens''' # Checa por qualquer bala que acertou os aliens, # e caso acerte exclui a bala e o alien collisions = pygame.sprite.groupcollide(self.bullets, self.aliens, True, True) if collisions: for aliens in collisions.values(): self.game_stats.score += self.settings.alien_points * \ len(aliens) self.scoreboard._score() self.scoreboard.check_highscore() if not self.aliens: # Destrói balas existentes self.bullets.empty() self._create_fleet() self.settings.increase_speed() self.game_stats.wave += 1 self.scoreboard._wave() def _update_screen(self): '''Preenche a tela com as imagens, e muda para um nova janela''' self.screen.fill(self.settings.bg_color) self.spaceship.draw_ship() for bullet in self.bullets.sprites(): bullet.draw_bullet() self.aliens.draw(self.screen) self.scoreboard.draw_score() if not self.game_stats.game_playing: # self.easy_game_button.draw_button() self.draw_buttons() pygame.display.flip() def draw_buttons(self): '''Desenha os botôes na tela''' self.easy_game_button.draw_button() self.normal_game_button.draw_button() self.hard_game_button.draw_button() def _check_aliens_in_bottom(self): '''Verifica se nenhum alien chegou na parte de baixo da tela''' screen_rect = self.screen.get_rect() # Passa por cada alien no grupo de aliens # verificando se encostou no limite de baixo da tela for alien in self.aliens.sprites(): if alien.rect.bottom >= screen_rect.bottom: self._spaceship_hit() break def _update_aliens(self): '''Atualiza a posição de todos os aliens da frota após verificar se a frota está no limite da janela''' self._check_fleet_edges() self.aliens.update() # Vê se um alien atingiu a nave, # e caso atinja o número de vidas diminui em 1 if pygame.sprite.spritecollideany(self.spaceship, self.aliens): self._spaceship_hit() self._check_aliens_in_bottom() def run_game(self): '''Inicia o loop principal do jogo''' while True: self.clock.tick(self.settings.fps) self._check_events() if self.game_stats.game_playing: self.spaceship.update() self._update_bullets() self._update_aliens() self._update_screen()