class MarioGame: """Overall class to manage game assets and behavior.""" def __init__(self): """Initialize the game, and create game resources.""" pygame.init() self.settings = Settings() self.stats = GameStats(self) #self.sb = Scoreboard self.screen = pygame.display.set_mode( (self.settings.screen_width, self.settings.screen_height)) self.mario = Mario(self) self.bowser = Bowser(self) self.iceballs = pygame.sprite.Group() self.fireballs = pygame.sprite.Group() # Make the Play button. self.play_button = Button(self, "Play") def run_game(self): """Start the main loop for the game.""" while True: self._check_events() if self.stats.game_active: self.mario.update() self._update_iceballs() self._update_fireballs() self._update_bowser() self._update_screen() def _start_game(self): # Reset the game settings. self.settings.initialize_dynamic_settings() # Reset game statistics. self.stats.reset_stats() self.stats.game_active = True # Get rid of any remaining aliens and bullets self.iceballs.empty() self.fireballs.empty() self.bowser.center_bowser() self.mario.center_mario() # Hide the mouse cursor. pygame.mouse.set_visible(False) def _check_events(self): """Respond to keypresses 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.MOUSEBUTTONDOWN: mouse_pos = pygame.mouse.get_pos() self._check_play_button(mouse_pos) def _check_keydown_events(self, event): """Respond to keypresses""" if event.key == pygame.K_UP: self.mario.moving_up = True elif event.key == pygame.K_DOWN: self.mario.moving_down = True elif event.key == pygame.K_RIGHT: self.mario.moving_right = True elif event.key == pygame.K_LEFT: self.mario.moving_left = True elif event.key == pygame.K_SPACE: self.fire_iceball() elif event.key == pygame.K_p: self._start_game() elif event.key == pygame.K_q: sys.exit() def _check_keyup_events(self, event): """Respond to keypresses""" if event.key == pygame.K_UP: self.mario.moving_up = False elif event.key == pygame.K_DOWN: self.mario.moving_down = False elif event.key == pygame.K_RIGHT: self.mario.moving_right = False elif event.key == pygame.K_LEFT: self.mario.moving_left = False 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: self._start_game() def _check_bowser_direction(self): if self.bowser.check_edges(): self.change_bowser_direction() def change_bowser_direction(self): self.settings.bowser_direction *= -1 def _check_bowser_collisions(self): for iceball in self.iceballs.copy(): if pygame.sprite.spritecollideany(self.bowser, self.iceballs): self.iceballs.remove(iceball) if self.stats.bowser_hp > 0: self.stats.bowser_hp -= 1 else: self.stats.game_active = False pygame.mouse.set_visible(True) def _check_mario_collisions(self): for fireball in self.fireballs.copy(): if pygame.sprite.spritecollideany(self.mario, self.fireballs): self.fireballs.remove(fireball) if self.stats.mario_hp > 0: self.stats.mario_hp -= 1 else: self.stats.game_active = False pygame.mouse.set_visible(True) def _check_projectile_collisions(self): for fireball in self.fireballs.copy(): if pygame.sprite.spritecollideany(fireball, self.iceballs): if fireball.fireball_hp > 0: fireball.fireball_hp -= 1 pygame.sprite.groupcollide(self.iceballs, self.fireballs, True, False) fireball.image = pygame.transform.scale( fireball.image, (60, 45)) else: pygame.sprite.groupcollide(self.iceballs, self.fireballs, True, True) def fire_iceball(self): """Create a new iceball and add it to the iceballs group.""" if len(self.iceballs) < self.settings.iceballs_allowed: new_iceball = Iceball(self) self.iceballs.add(new_iceball) def fire_fireball(self): """Create a new fireball and add it to the fireballs group.""" if len(self.fireballs) < self.settings.fireballs_allowed: new_fireball = Fireball(self) self.fireballs.add(new_fireball) def bowser_fireball_chance(self): if -120 <= self.bowser.y - self.mario.y <= 120: self.fireball_chance = self.settings.fireball_chance else: self.fireball_chance = 0 def bowser_moving_chance(self): if self.settings.bowser_direction == 1 and self.mario.y <= self.bowser.y: self.movement_chance = self.settings.movement_chance elif self.settings.bowser_direction == 1 and self.mario.y > self.bowser.y: self.movement_chance = -1 * self.settings.movement_chance elif self.settings.bowser_direction == -1 and self.mario.y >= self.bowser.y: self.movement_chance = self.settings.movement_chance elif self.settings.bowser_direction == -1 and self.mario.y < self.bowser.y: self.movement_chance = -1 * self.settings.movement_chance def _update_iceballs(self): """Update the position of iceballs and get rid of old iceballs.""" # Update iceball positions. self.iceballs.update() # Get rid of iceballs that have disappeared for iceball in self.iceballs.copy(): if iceball.rect.left >= self.settings.screen_width: self.iceballs.remove(iceball) self._check_bowser_collisions() def _update_fireballs(self): """Update the position of fireballs and get rid of old fireballs.""" # Update fireball positions. self.fireballs.update() # Get rid of fireballs that have disappeared for fireball in self.fireballs.copy(): if fireball.rect.right <= 0: self.fireballs.remove(fireball) self._check_mario_collisions() self._check_projectile_collisions() def _update_bowser(self): self._check_bowser_direction() self.bowser.update() self.bowser_fireball_chance() self.bowser_moving_chance() if randint(1, 500 - self.fireball_chance) == 1: self.fire_fireball() if randint(1, 800 - self.movement_chance) == 1: self.change_bowser_direction() def _update_screen(self): """Update images on the screen, and flip to the new screen.""" self.screen.fill(self.settings.bg_color) self.mario.blitme() self.bowser.blitme() self.iceballs.draw(self.screen) self.fireballs.draw(self.screen) # Draw the play button if the game is inactive. if not self.stats.game_active: self.play_button.draw_button() pygame.display.flip()
class AlienInvasion: """Overall class to manage game assets and behavior.""" def __init__(self): """Initialize the game, and create game resources.""" pygame.init() self.settings = Settings() 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('Alien Invasion') # Create an instance to store game statistics, # and create a scoreboard. self.stats = GameStats(self) self.sb = Scoreboard(self) self.mario = Mario(self) self.bullets = pygame.sprite.Group() self.aliens = pygame.sprite.Group() self._create_fleet() # Make the play button. self.play_button = Button(self, 'Play') def run_game(self): """Start the main loop for the game.""" while True: self._check_events() if self.stats.game_active: self.mario.update() self._update_bullets() self._update_aliens() self._update_screen() def _check_events(self): """Respond to keypresses and mouse events.""" for event in pygame.event.get(): if event.type == pygame.QUIT: self.stats.save_high_score() 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_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: # Reset the game settings. self.settings.initialize_dynamic_settings() # Reset the game statistics. self.stats.reset_stats() self.stats.game_active = True self.sb.prep_images() # Get rid of any remaining aliens and bullets. self.aliens.empty() self.bullets.empty() # Create a new fleet and center mario. self._create_fleet() self.mario.center_mario() # Hide the mouse cursor. pygame.mouse.set_visible(False) # Play music. pygame.mixer.music.load('sounds/mario_theme.mp3') pygame.mixer.music.play(loops=-1, start=1.5) def _check_keydown_events(self, event): """Respond to keypresses.""" if event.key == pygame.K_RIGHT: self.mario.moving_right = True elif event.key == pygame.K_LEFT: self.mario.moving_left = True elif event.key == pygame.K_q: self.stats.save_high_score() sys.exit() elif event.key == pygame.K_SPACE: self._fire_bullet() def _check_keyup_events(self, event): """Respond to key releases.""" if event.key == pygame.K_RIGHT: self.mario.moving_right = False elif event.key == pygame.K_LEFT: self.mario.moving_left = False def _update_bullets(self): """Update position of bullets and get rid of old bullets.""" # Update bullet positions. 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.sb.prep_score() self.sb.check_high_score() if not self.aliens: self._start_new_level() def _start_new_level(self): """Start a new level.""" # Destroy existing bullets and create new fleet. self.bullets.empty() self._create_fleet() self.settings.increase_speed() # Increase level. self.stats.level += 1 self.sb.prep_level() def _update_aliens(self): """ Check if the fleet is at an edge, then update the positions of all aliens in the fleet. """ self._check_fleet_edges() self.aliens.update() # Look for alien-mario collisions. if pygame.sprite.spritecollideany(self.mario, self.aliens): self._mario_hit() # Look for aliens hitting the bottom of the screen. self._check_aliens_bottom() 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: # Treat this the same as if mario got hit. self._mario_hit() break def _mario_hit(self): """Respond to mario being hit by an alien.""" # Play death sound. pygame.mixer.music.load('sounds/death_sound.mp3') pygame.mixer.music.play(start=0.5) # Update mario one last time. self.mario.destroy_mario() self._update_screen() # Reset the round if there are more lives left. if self.stats.marios_left > 0: # Decrement marios_left, and update scoreboard. self.stats.marios_left -= 1 self.sb.prep_marios() # Get rid any remaining aliens and bullets. self.aliens.empty() self.bullets.empty() # Create a new fleet and center mario. self._create_fleet() self.mario.center_mario() # Pause. sleep(3.5) # Play music. pygame.mixer.music.load('sounds/mario_theme.mp3') pygame.mixer.music.play(loops=-1, start=1.5) else: self.stats.game_active = False pygame.mouse.set_visible(True) def _create_fleet(self): """Create the fleet of aliens.""" # 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 available_space_x = self.settings.screen_width - (2 * alien_width) number_aliens_x = available_space_x // (2 * alien_width) # Determine the number of rows of aliens that can fit on the screen. mario_height = self.mario.rect.height available_space_y = (self.settings.screen_height - (3 * alien_height) - mario_height) number_rows = available_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 = 2 * alien.rect.height + 2 * alien.rect.height * row_number self.aliens.add(alien) def _check_fleet_edges(self): """Respond appropriately if any aliens have reached an edge.""" for alien in self.aliens.sprites(): if alien.check_edges(): self._change_fleet_direction() 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 self.settings.fleet_direction *= -1 def _update_screen(self): """Update images on the screen, and flip to the new screen.""" self.screen.fill(self.settings.bg_color) self.mario.blitme() self.bullets.draw(self.screen) self.aliens.draw(self.screen) # Draw the score information. self.sb.show_score() # Draw the play button if the game is inactive. if not self.stats.game_active: self.play_button.draw_button() pygame.display.flip() 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)