diff --git a/alien_invasion.py b/alien_invasion.py index 0486891..43de0af 100644 --- a/alien_invasion.py +++ b/alien_invasion.py @@ -3,6 +3,7 @@ from time import sleep import pygame from settings import Settings from game_stats import GameStats +from score_board import ScoreBoard from button import Button from ship import Ship from bullet import Bullet @@ -23,6 +24,7 @@ class AlienInvasion: pygame.display.set_caption("Alien Invasion") self.bg_color = self.settings.bg_color self.stats = GameStats(self) + self.score_board = ScoreBoard(self) self.ship = Ship(self) self.bullets = Group() self.aliens = Group() @@ -49,7 +51,7 @@ class AlienInvasion: alien = Alien(self) alien_width, alien_height = alien.rect.size current_x, current_y = alien_width, alien_height - while current_y < (self.settings.screen_height - 3 * alien_height): + while current_y < (self.settings.screen_height - 3 * alien_height) and current_y < 10 * alien_height: while current_x < (self.settings.screen_width - 2 * alien_width): self._create_alien(current_x, current_y) current_x += 2 * alien_width @@ -112,7 +114,11 @@ class AlienInvasion: """Start a new game when the player clicks Play.""" button_clicked = self.play_button.rect.collidepoint(mouse_pos) if button_clicked and not self.game_active: + self.settings.initialize_dynamic_settings() self.stats.reset_stats() + self.score_board.prep_score() + self.score_board.prep_level() + self.score_board.prep_ships() self.game_active = True self.bullets.empty() self.aliens.empty() @@ -145,16 +151,29 @@ class AlienInvasion: def _check_bullet_alien_collisions(self): """Respond to bullet-alien collisions.""" 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.score_board.prep_score() + self.score_board.check_high_score() + self.score_board.prep_level() + self.score_board.prep_ships() + if not self.aliens: # If the fleet is empty, create a new fleet. self.bullets.empty() self._create_fleet() + self.settings.increase_speed() + self.stats.level += 1 + self.score_board.prep_level() def _ship_hit(self): """Respond to the ship being hit by an alien.""" if self.stats.ships_left > 0: # Decrement ships_left and reset the game state. self.stats.ships_left -= 1 + self.score_board.prep_ships() self.bullets.empty() self.aliens.empty() self._create_fleet() @@ -180,6 +199,7 @@ class AlienInvasion: bullet.draw_bullet() self.ship.blitme() self.aliens.draw(self.screen) + self.score_board.show_score() if not self.game_active: self.play_button.draw_button() pygame.display.flip() diff --git a/game_stats.py b/game_stats.py index bb65119..0a5aee5 100644 --- a/game_stats.py +++ b/game_stats.py @@ -5,8 +5,10 @@ class GameStats: """Initialize statistics.""" self.settings = ai_game.settings self.reset_stats() + self.high_score = 0 def reset_stats(self): """Initialize statistics that can change during the game.""" self.ships_left = self.settings.ship_limit - self.score = 0 \ No newline at end of file + self.score = 0 + self.level = 1 diff --git a/score_board.py b/score_board.py new file mode 100644 index 0000000..0acb1e8 --- /dev/null +++ b/score_board.py @@ -0,0 +1,80 @@ +import pygame.font +from pygame.sprite import Group +from ship import Ship + +class ScoreBoard: + """Class to report scoring information.""" + + def __init__(self, ai_game): + """Initialize scorekeeping attributes.""" + self.ai_game = ai_game + self.screen = ai_game.screen + self.screen_rect = self.screen.get_rect() + self.settings = ai_game.settings + self.stats = ai_game.stats + + # Font settings for scoring information. + self.text_color = (30, 30, 30) + self.font = pygame.font.SysFont(None, 48) + + # Prepare the initial score image. + self.prep_score() + self.prep_high_score() + self.prep_level() + self.prep_ships() + + def prep_score(self): + """Turn the score into a rendered image.""" + rounded_score = round(self.stats.score, -1) + score_str = f"{rounded_score:,}" + self.score_image = self.font.render(score_str, True, self.text_color, + self.settings.bg_color) + # Display the score at the top right of the screen. + self.score_rect = self.score_image.get_rect() + self.score_rect.right = self.screen_rect.right - 20 + self.score_rect.top = 20 + + def prep_high_score(self): + """Turn the high score into a rendered image.""" + high_score = round(self.stats.high_score, -1) + high_score_str = f"{high_score:,}" + self.high_score_image = self.font.render(high_score_str, True, + self.text_color, self.settings.bg_color) + + # Center the high score at the top of the screen. + self.high_score_rect = self.high_score_image.get_rect() + self.high_score_rect.centerx = self.screen_rect.centerx + self.high_score_rect.top = self.score_rect.top + + def prep_level(self): + """Turn the level into a rendered image.""" + level_str = str(self.stats.level) + self.level_image = self.font.render(level_str, True, self.text_color, + self.settings.bg_color) + + # Position the level below the score. + self.level_rect = self.level_image.get_rect() + self.level_rect.right = self.score_rect.right + self.level_rect.top = self.score_rect.bottom + 10 + + def prep_ships(self): + """Show how many ships are left.""" + self.ships = Group() + for ship_number in range(self.stats.ships_left): + ship = Ship(self.ai_game) + ship.rect.x = 10 + ship_number * ship.rect.width + ship.rect.y = 10 + self.ships.add(ship) + + def show_score(self): + """Draw the score and high score to the screen.""" + self.screen.blit(self.score_image, self.score_rect) + self.screen.blit(self.high_score_image, self.high_score_rect) + self.screen.blit(self.level_image, self.level_rect) + self.ships.draw(self.screen) + + def check_high_score(self): + """Check to see if there's a new high score.""" + if self.stats.score > self.stats.high_score: + self.stats.high_score = self.stats.score + self.prep_high_score() \ No newline at end of file diff --git a/settings.py b/settings.py index 93f7b7d..3318751 100644 --- a/settings.py +++ b/settings.py @@ -21,4 +21,26 @@ class Settings: # Alien settings self.alien_speed = 1.0 self.fleet_drop_speed = 10 + + self.speedup_scale = 1.1 + self.score_scale = 1.5 + + self.initialize_dynamic_settings() + + def initialize_dynamic_settings(self): + """Initialize settings that change during the game.""" + self.ship_speed = 1.5 + self.bullet_speed = 3.0 + self.alien_speed = 1.0 self.fleet_direction = 1 # 1 represents right; -1 represents left + + # Scoring + self.alien_points = 50 + + def increase_speed(self): + """Increase speed settings and alien point values.""" + self.ship_speed *= self.speedup_scale + self.bullet_speed *= self.speedup_scale + self.alien_speed *= self.speedup_scale + + self.alien_points = int(self.alien_points * self.score_scale) diff --git a/ship.py b/ship.py index caa28be..bb00655 100644 --- a/ship.py +++ b/ship.py @@ -1,10 +1,12 @@ import pygame +from pygame.sprite import Sprite -class Ship: +class Ship(Sprite): """A class to manage the ship.""" def __init__(self, ai_game): """Initialize the ship and set its starting position.""" + super().__init__() self.screen = ai_game.screen self.settings = ai_game.settings self.image = pygame.image.load('images/ship.bmp')