Step 1: Merge the code. After merging, the test can be run directly. There are 405 lines of code in total.
Step 2: Delete duplicate import statements
pygame.font does not need to be introduced separately
The settings, game_stats, button, scoreboard, ship, and alien classes are directly defined in the file and do not need to be introduced again.
The functions in the game_factions class are defined directly in the file and do not need to be introduced. Delete and modify the name when the function is called (remove the alias gf)
There are still 381 lines of code left, and the test runs without any problems.
Step 3: Adjust the order of the following categories
Step 4: Analyze the streamlined code
Add the variable screen_rect and pass it as a parameter to reduce the use of self.screen=screen and self.screen_rect=self.screen.get_rect()
There are still 378 lines of code left, and the test runs without problems.
Step 5: Function part
Adjust functions according to the logical order of program operation, reduce function names and function calls, and reduce function nesting
Step 6: Reduce unnecessary calculation functions. The number of aliens in each row is 9 and the number of rows is 4. There is no need to pass the ship parameter.
Step 7: Use the unchanged value directly to reduce the number of variables
After completion, the code will be within 300 lines and all functions will remain unchanged.
end.
Attach all code
import pygame from pygame.sprite import Sprite from pygame.sprite import Group importsys from time import sleep class Settings(): def initialize_dynamic_settings(self): #Dynamic settings, the value will be increased accordingly after the level is increased self.ship_speed_factor = 1.5 self.bullet_speed_factor = 3 self.alien_speed_factor = 1 self.fleet_direction = 1 # 1 means right, -1 means left self.alien_points = 50 def increase_speed(self): self.ship_speed_factor *= 1.1 self.bullet_speed_factor *= 1.1 self.alien_speed_factor *= 1.1 self.alien_points = int(self.alien_points * 1.5) class GameStats(): def __init__(self): self.reset_stats() self.game_active = False self.high_score = 0 def reset_stats(self): self.ships_left = 3 self.score = 0 self.level = 1 classButton(): def __init__(self,msg,screen_rect): self.rect = pygame.Rect(0,0,200,50) self.rect.center = screen_rect.center self.prep_msg(msg) def prep_msg(self,msg): self.msg_image = pygame.font.SysFont(None,48).render(msg,True,(255,255,255),(0,255,0)) self.msg_image_rect = self.msg_image.get_rect() self.msg_image_rect.center = self.rect.center def draw_button(self,screen): screen.fill((0,255,0),self.rect) # display rectangle screen.blit(self.msg_image,self.msg_image_rect) # display text Play class Scoreboard(): def __init__(self, ai_settings, stats, screen_rect, screen): self.ai_settings = ai_settings self.stats = stats self.prep_score() # Current score self.prep_high_score(screen_rect) # highest score self.prep_level() #Current level self.prep_ships(screen,screen_rect) # The number of remaining spaceships def prep_score(self): rounded_score = int(round(self.stats.score,-1)) # -1 means rounding to the left of the decimal point score_str = "{:,}".format(rounded_score) # thousands separator self.score_image = pygame.font.SysFont(None,48).render(score_str,True,(30,30,30),(230,230,230)) self.score_rect = self.score_image.get_rect() self.score_rect.right = 1180 self.score_rect.top = 20 def prep_high_score(self,screen_rect): high_score = int(round(self.stats.high_score,-1)) high_score_str = "{:,}".format(high_score) self.high_score_image =pygame.font.SysFont(None,48).render(high_score_str,True,(30,30,30),(230,230,230)) self.high_score_rect = self.high_score_image.get_rect() self.high_score_rect.centerx = screen_rect.centerx self.high_score_rect.top = 20 def prep_level(self): self.level_image = pygame.font.SysFont(None,48).render(str(self.stats.level),True,(30,30,30),(230,230,230)) self.level_rect = self.level_image.get_rect() self.level_rect.right = 1180 self.level_rect.top = self.score_rect.bottom + 10 def prep_ships(self,screen,screen_rect): self.ships = Group() for ship_number in range(self.stats.ships_left): # Use the number of pictures to represent the number of remaining ships ship = Ship(screen,self.ai_settings,screen_rect) ship.rect.x = 10 + ship_number * ship.rect.width ship.rect.y = 10 self.ships.add(ship) def show_score(self,screen): screen.blit(self.score_image,self.score_rect) screen.blit(self.high_score_image,self.high_score_rect) screen.blit(self.level_image,self.level_rect) self.ships.draw(screen) class Ship(Sprite): def __init__(self,screen,ai_settings,screen_rect): super().__init__() self.screen = screen self.ai_settings = ai_settings self.image = pygame.image.load("images/ship.bmp") self.rect = self.image.get_rect() self.rect.centerx = screen_rect.centerx self.rect.bottom = screen_rect.bottom self.center = float(self.rect.centerx) self.moving_right = False self.moving_left = False def update(self): if self.moving_right and self.rect.right < 1200: self.center + = self.ai_settings.ship_speed_factor if self.moving_left and self.rect.left > 0: self.center -= self.ai_settings.ship_speed_factor self.rect.centerx = self.center def blitme(self): self.screen.blit(self.image,self.rect) def center_ship(self,screen_rect): self.center = screen_rect.centerx class Bullet(Sprite): def __init__(self,ai_settings,ship): super().__init__() self.rect = pygame.Rect(0,0,3,15) self.rect.centerx = ship.rect.centerx self.rect.top = ship.rect.top self.y = float(self.rect.y) self.speed_factor = ai_settings.bullet_speed_factor def update(self): self.y -= self.speed_factor self.rect.y = self.y def draw_bullet(self,screen): pygame.draw.rect(screen,(60,60,60),self.rect) class Alien(Sprite): def __init__(self,ai_settings): super().__init__() self.ai_settings = ai_settings self.image = pygame.image.load("images/alien.bmp") self.rect = self.image.get_rect() self.rect.x = self.rect.width self.rect.y = self.rect.height self.x = float(self.rect.x) def update(self): self.x + = self.ai_settings.alien_speed_factor * self.ai_settings.fleet_direction self.rect.x = self.x def check_events(ship,ai_settings,bullets,play_button,stats,aliens,sb,screen_rect,screen): #Event loop for event in pygame.event.get(): if event.type == pygame.QUIT: sys. exit() elif event.type == pygame.KEYDOWN: if event.key == pygame.K_RIGHT: ship.moving_right = True elif event.key == pygame.K_LEFT: ship.moving_left = True elif event.key == pygame.K_SPACE: if len(bullets) < 3: # Fire, fire bullets and join the group new_bullet = Bullet(ai_settings,ship) bullets.add(new_bullet) elif event.key == pygame.K_q: sys. exit() elif event.type == pygame.KEYUP: if event.key == pygame.K_RIGHT: ship.moving_right = False elif event.key == pygame.K_LEFT: ship.moving_left = False elif event.type == pygame.MOUSEBUTTONDOWN: mouse_x, mouse_y = pygame. mouse. get_pos() check_play_button(play_button,mouse_x,mouse_y,stats,aliens,bullets,ai_settings,ship,sb,screen_rect,screen) def check_play_button(play_button,mouse_x,mouse_y,stats,aliens,bullets,ai_settings,ship,sb,screen_rect,screen): button_clicked = play_button.rect.collidepoint(mouse_x,mouse_y) if button_clicked and not stats.game_active: # Click the Play button ai_settings.initialize_dynamic_settings() pygame.mouse.set_visible(False) #Hide the mouse in the game stats.reset_stats() stats.game_active = True sb.prep_score() sb. prep_high_score(screen_rect) sb.prep_level() sb. prep_ships(screen, screen_rect) aliens.empty() bullets.empty() create_fleet(ai_settings, aliens) ship. center_ship(screen_rect) def update_bullets(bullets,aliens,ai_settings,stats,sb,screen_rect): bullets.update() # Update bullet position for bullet in bullets.copy(): # Detect bullets that reach the top of the screen and delete them if bullet.rect.bottom <= 0: bullets.remove(bullet) collisions = pygame.sprite.groupcollide(bullets,aliens,False,True) # Bullet and alien collision detection if collisions: for aliens in collisions. values(): stats.score + = ai_settings.alien_points * len(aliens) sb.prep_score() if stats.score > stats.high_score: # Check the highest score stats.high_score = stats.score sb. prep_high_score(screen_rect) if len(aliens) == 0: bullets.empty() ai_settings.increase_speed() stats.level + = 1 sb.prep_level() create_fleet(ai_settings,aliens) def create_fleet(ai_settings,aliens): # Create an alien group for row_number in range(4): for alien_number in range(9): alien = Alien(ai_settings) alien_width = alien.rect.width 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 aliens.add(alien) def ship_hit(stats,aliens,bullets,ship,ai_settings,sb,screen,screen_rect): # Reset the game after a ship collision if stats.ships_left > 0: stats.ships_left -= 1 sb.prep_ships(screen,screen_rect) aliens. empty() bullets. empty() create_fleet(ai_settings,aliens) ship.center_ship(screen_rect) sleep(0.5) else: stats.game_active = False pygame.mouse.set_visible(True) def update_aliens(aliens,ai_settings,ship,stats,bullets,screen_rect,sb,screen): for alien in aliens.sprites(): # When reaching the edge of the screen, move downward and change the direction of movement if alien.rect.right >= 1200 or alien.rect.left <= 0: for alien in aliens.sprites(): alien.rect.y += 10 ai_settings.fleet_direction *= -1 break aliens. update() if pygame.sprite.spritecollideany(ship,aliens): # Collision detection between ship and aliens ship_hit(stats, aliens, bullets, ship, ai_settings, sb, screen, screen_rect) for alien in aliens.sprites(): if alien.rect.bottom >= screen_rect.bottom: ship_hit(stats, aliens, bullets, ship, ai_settings, sb, screen, screen_rect) break def run_game(): pygame.init() ai_settings = Settings() screen = pygame.display.set_mode((1200,800)) screen_rect = screen. get_rect() pygame.display.set_caption("Alien Invasion") stats = GameStats() play_button = Button("Play",screen_rect) sb = Scoreboard(ai_settings,stats,screen_rect,screen) ship = Ship(screen,ai_settings,screen_rect) bullets = Group() aliens = Group() create_fleet(ai_settings, aliens) while True: screen.fill((230,230,230)) check_events(ship, ai_settings, bullets, play_button, stats, aliens, sb, screen_rect, screen) if stats. game_active: ship. update() update_bullets(bullets, aliens, ai_settings, stats, sb, screen_rect) update_aliens(aliens, ai_settings, ship, stats, bullets, screen_rect, sb, screen) for bullet in bullets. sprites(): bullet. draw_bullet(screen) ship. blitme() aliens.draw(screen) sb. show_score(screen) if not stats. game_active: play_button. draw_button(screen) pygame.display.flip() run_game()