2. Improve the level: divide the game settings into static and dynamic groups. For settings that change with the game, make sure they are reset when you start a new game.
The settings module defines the speed increase rate speedup_scale. New method initialize_dynamic_settings(), put the settings that will change with the progress of the game in this method to set the initial value. Then create a new method, increase_speed() method to increase the speed of the setting to be changed regularly.
game_funciton module to function star_game() and check_ bullet_ alien_ Collections () calls initialize separately_ dynamic_ Settings () and increase_speed() method
settings.py code is as follows:
# -*- coding: GBK -*- class Settings(): '''Store all set classes of alien invasion''' def __init__(self): '''Initialize the static settings of the game''' # screen setting self.screen_width = 1200 self.screen_height = 650 self.bg_color = (230, 230, 230) # Spacecraft settings self.ship_limit = 3 # Number of spacecraft # Bullet setting self.bullet_width = 3 self.bullet_height = 15 self.bullet_color = 60, 60, 60 self.bullets_allowed = 3 # Limit the number of bullets # Alien settings self.fleet_drop_speed = 10 #Descent speed # What kind of speed to accelerate the pace of the game self.speedup_scale = 1.1 self.initialize_dynamic_settings() def initialize_dynamic_settings(self): '''Initialize settings that change as the game progresses''' self.alien_speed_factor = 1.5 #Alien left and right movement speed self.bullet_speed_factor = 3 #Bullet speed self.ship_speed_factor = 1.5 #Spacecraft movement speed # fleet_ A direction of 1 means to move to the right, and a direction of - 1 means to move to the left self.fleet_direction = 1 def increase_speed(self): '''Increase speed setting''' self.alien_speed_factor *= self.speedup_scale self.bullet_speed_factor *= self.speedup_scale self.ship_speed_factor *= self.speedup_scale
game_ functions. The functions modified by py are as follows:
def start_game(ai_settings, screen, stats, ship, aliens, bullets): '''In press Q Key or mouse click Play Button to start the game''' # Reset game settings ai_settings.initialize_dynamic_settings() # hide cursor pygame.mouse.set_visible(False) # Reset game statistics stats.reset_stats() stats.game_active = True #Clear alien list and bullet list aliens.empty() bullets.empty() #Create a new group of aliens and center the spacecraft create_fleet(ai_settings, screen, ship, aliens) ship.center_ship()
def check_bullet_alien_collisions(ai_settings, screen, ship, aliens, bullets): '''In response to the collision between bullets and aliens''' # Delete bullets and aliens in collision collisions = pygame.sprite.groupcollide(bullets, aliens, True, True) #Whenever bullets and alien rect s overlap, Pygame deletes the bullets and aliens that collide if len(aliens) == 0: # If the alien population is wiped out, delete the existing bullets and create a new group of aliens bullets.empty() #The method empty() deletes all remaining sprites in the group ai_settings.increase_speed() #Speed up the game create_fleet(ai_settings, screen, ship, aliens) #Create alien groups
3. Scoring: track the player's score in real time, and display the highest score, current level and the number of remaining ships.
(1) Display score: first reset in GameStats class_ Add the score attribute to the stats () method. In order to display the score on the screen, we created a new class Scoreboard, which is also used to display the highest score, level and the number of remaining ships. This class imports pyGame Font class, which can display text on the screen, convert text into image, and use font Render() function and set the text display position, show_ The core () function calls screen Blit() displays the image to the specified position on the screen. alien_invasion.py creates an instance of the Scoreboard class sb. game_ Modify update in functions module_ The screen() function calls show_score() displays all the information to be displayed on the Scoreboard. To calculate the score, you need to add alien points in the settings module (the value can be increased with the game), check_ bullet_ alien_ In the collections() function, the current score is obtained according to the sum of the product of the number of aliens in each list and the number of points in all values of the collections dictionary. Round the score to a multiple of 10, and use the function round() to specify the second argument as a negative number; Thousands of separators represented by commas are added to large numbers: use string format instruction, "{:}" format()
(2) Highest score: add the highest score high to the default method of Gamestats_ Score, and then add the method prep to convert the highest score into the rendered image in the Scoreboard class_ high_score(),show_ The score () method displays the highest score image on the screen. game_ New function check in functions module_ high_score() checks whether the highest score is generated and checks_ bullet_ alien_ The collisions () function calls the function to update the highest score after calculating the current score code.
(3) Display level: reset of Gamestats_ Add the level attribute in the stats () method, and add the method prep to convert the level into the rendered image_ Level(), and in show_ The score () method displays the level on the screen. check_ bullet_ alien_ In the collections() function, if the whole group of aliens is eliminated, the level will be increased. To ensure that the scoreboard information is updated when starting a new game, game is required_ Start of functions module_ The game () function calls prep_ after resetting the game statistics. score(),prep_high_score() and prep_ The three methods of level () reset the scoreboard image and modify the number of parameters related to the function.
(4) Display the number of remaining ships: (use the aircraft image to display the number of remaining ships) first, let Ship inherit Sprite so that the Ship group can be created. Import Ship class into scoreboard module and create prep_ships() method to display how many ships are left. Modify show_ The score () function adds the code to draw the spaceship. game_ Star in functions module_ In the game() function, call prep at the code that resets the scoreboard image_ Ships (), modify ship_hit() function, ships after the spacecraft is hit_ After left minus 1, call prep_. Ships() updates the scoreboard. And modify the function calling the function to increase the number of parameters.
game_stats.py code is as follows:
# -*- coding: GBK -*- class GameStats(): '''Track game statistics''' def __init__(self, ai_settings): '''Initialization statistics''' self.ai_settings = ai_settings self.reset_stats() # Make the game inactive at the beginning self.game_active = False # Under no circumstances should the highest score be reset self.high_score = 0 def reset_stats(self): '''Initializes statistics that may change during game operation''' self.ships_left = self.ai_settings.ship_limit self.core = 0 #Current score self.level = 1 #Current level
settings.py code is as follows:
# -*- coding: GBK -*- class Settings(): '''Store all set classes of alien invasion''' def __init__(self): '''Initialize the static settings of the game''' # screen setting self.screen_width = 1200 self.screen_height = 650 self.bg_color = (230, 230, 230) # Spacecraft settings self.ship_limit = 3 # Number of spacecraft # Bullet setting self.bullet_width = 3 self.bullet_height = 15 self.bullet_color = 60, 60, 60 self.bullets_allowed = 3 # Limit the number of bullets # Alien settings self.fleet_drop_speed = 10 #Descent speed # What kind of speed to accelerate the pace of the game self.speedup_scale = 1.1 # Increase speed of alien points self.score_scale= 1.5 self.initialize_dynamic_settings() def initialize_dynamic_settings(self): '''Initialize settings that change as the game progresses''' self.alien_speed_factor = 1.5 #Alien left and right movement speed self.bullet_speed_factor = 3 #Bullet speed self.ship_speed_factor = 1.5 #Spacecraft movement speed # fleet_ A direction of 1 means to move to the right, and a direction of - 1 means to move to the left self.fleet_direction = 1 # scoring self.alien_points = 50 def increase_speed(self): '''Increase speed setting''' self.alien_speed_factor *= self.speedup_scale self.bullet_speed_factor *= self.speedup_scale self.ship_speed_factor *= self.speedup_scale self.alien_points = int(self.alien_point * self.score_scale) #print(self.alien_points)
ship.py code is as follows:
# -*- coding: GBK -*- import pygame from pygame.sprite import Sprite #In order to display the number of remaining ships on the scoreboard class Ship(Sprite): def __init__(self, ai_settings, screen): #The parameter screen specifies where the spacecraft is to be drawn '''Initialize the spacecraft and set its initial position''' super().__init__() self.screen = screen self.ai_settings = ai_settings # Introduce the setting instance and use the ship speed attribute in the instance_ speed_ factor # Load the ship image and obtain its circumscribed rectangle self.image = pygame.image.load('images/ship.bmp') #Load the image and return a surface representing the spacecraft self.rect = self.image.get_rect() #get_rect() gets the property rect of the corresponding surface self.screen_rect = screen.get_rect() #get_rect() gets the rectangle (rect object) representing the screen and the property rect of the corresponding surface # Place each new spacecraft in the bottom center of the screen self.rect.centerx = self.screen_rect.centerx #Set the x coordinate of the spacecraft center to the property centerx representing the rectangle of the screen self.rect.bottom = self.screen_rect.bottom #Set the y coordinate of the lower edge of the spaceship to the attribute bottom representing the rectangle of the screen # Store small values in the attribute center of the aircraft self.center = float(self.rect.centerx) #Attribute values such as centerx of rect can only store integer values # Move flag self.moving_right = False self.moving_left = False def update(self): '''Adjust the position of the spacecraft according to the moving sign''' # Update the center value of the ship instead of rect if self.moving_right and self.rect.right < self.screen_rect.right: #The statement after and ensures that the spacecraft does not move outside the right screen self.center += self.ai_settings.ship_speed_factor if self.moving_left and self.rect.left > 0: #The statement after and ensures that the spacecraft does not move outside the left screen self.center -= self.ai_settings.ship_speed_factor # According to self Center Update rect object self.rect.centerx = self.center #Only self. Is stored here The integer part of the center has little effect on the aircraft display def blitme(self): '''Draw the spaceship at the specified location''' self.screen.blit(self.image, self.rect) #According to self Rect draws the ship image to the screen at the specified position def center_ship(self): '''Center the ship on the screen''' self.center = self.screen_rect.centerx
scoreboard.py code is as follows:
# -*- coding: GBK -*- import pygame.font #Used to render text to the screen #from pygame.sprite import Sprite from pygame.sprite import Group #Import the Group class for creating a spaceship Group from ship import Ship class Scoreboard(): '''Class that displays score information''' def __init__(self, ai_settings, screen, stats): '''Initialize the value involved in displaying the score''' self.screen = screen self.screen_rect = screen.get_rect() self.ai_settings = ai_settings self.stats = stats # Font settings used when displaying score information self.text_color = (30, 30, 30) self.font = pygame.font.SysFont(None, 48) # Prepare an image that contains the highest score and the current score self.prep_score() self.prep_high_score() self.prep_level() self.prep_ships() def prep_score(self): '''Convert the score into a rendered image''' rounded_score = int(round(self.stats.score, -1)) #If the integer and real parameter are rounded to the second decimal place, it is usually the number of decimal places after the round() to the second decimal place score_str = "{:,}".format(rounded_score) #A string formatting instruction is used here to insert a comma when converting a numeric value to a string. self.score_image = (score_str, True, self.text_color, self.ai_settings.bg_color) #Call font Render() converts the text into an image. The Boolean argument specifies whether the anti aliasing function is turned on or off (anti aliasing makes the edge of the text smoother). The last two arguments are text color and background color respectively # Place the score in the upper right corner 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): '''Converts the highest score to a rendered image''' high_score = int(round(self.stats.high_score, -1)) high_score_str = "{:,}".format(high_score) self.high_score_image = self.font.render(high_score_str, True, self.text_color, self.ai_settings.bg_color) # Place the highest score at the top center 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): '''Convert levels to rendered images''' self.level_image = self.font.render(str(self.stats.level), True, self.text_color, self.ai_settings.bg_color) # Displays the rating 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() #Create an empty group for ship_number in range(self.stats.ships_left): ship = Ship(self.ai_settings, self.screen) ship.rect.x = 10 + ship_number * ship.rect.width ship.rect.y = 10 self.ships.add(ship) def show_score(self): '''Display the ship and score on the screen''' self.screen.blit(self.score_image, self.score_rect) #Draw the current score image self.screen.blit(self.high_score_image, self.high_score_rect) #Draw the highest score image self.screen.blit(self.level_image, self.level_rect) #Draw current level image # Drawing spacecraft self.ships.draw(self.screen)
game_functions.py code is as follows:
# -*- coding: GBK -*- import sys # Use the module sys to exit the game. from time import sleep # The sleep() function can be used to pause the game import pygame from bullet import Bullet from alien import Alien # Import the alien module alien class to control the behavior of each alien def check_keydown_events(event, ai_settings, screen, stats, sb, ship, aliens, bullets): '''Response key''' 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: # Blank key fire_bullet(ai_settings, screen, ship, bullets) elif event.key == pygame.K_q: # Letter Q key sys.exit() elif event.key == pygame.K_p: # When the game is inactive, press the P key to start the game if not stats.game_active: start_game(ai_settings, screen, stats, sb, ship, aliens, bullets) def fire_bullet(ai_settings, screen, ship, bullets): '''If the limit is not reached, fire a bullet''' # Create a new bullet and add it to the group bullets if len(bullets) < ai_settings.bullets_allowed: # Limit the number of bullets new_bullet = Bullet(ai_settings, screen, ship) bullets.add(new_bullet) def check_keyup_events(event, ship): '''Response release''' if event.key == pygame.K_RIGHT: ship.moving_right = False elif event.key == pygame.K_LEFT: ship.moving_left = False def check_events(ai_settings, screen, stats, sb, play_button, ship, aliens, bullets): '''Respond to key and mouse events''' # Monitor keyboard and mouse events for event in pygame.event.get(): #Time detected by Pygame if event.type == pygame.QUIT: #If the player clicks the window close button, pyGame is detected Quit event. sys.exit() #Exit the game elif event.type == pygame.KEYDOWN: #Press and hold the key to modify the value of the move flag check_keydown_events(event, ai_settings, screen, stats, sb, ship, aliens, bullets) elif event.type == pygame.KEYUP: #Modify the value of the movement flag according to the release key check_keyup_events(event, ship) elif event.type == pygame.MOUSEBUTTONDOWN: mouse_x, mouse_y = pygame.mouse.get_pos() #get_pos() returns a primitive, containing the x and y coordinates of the mouse when clicked check_play_button(ai_settings, screen, stats, sb, play_button, ship, aliens, bullets, mouse_x, mouse_y) def check_play_button(ai_settings, screen, stats, sb, play_button, ship, aliens, bullets, mouse_x, mouse_y): '''Click on the player Play Button to start a new game''' button_clicked = play_button.rect.collidepoint(mouse_x, mouse_y) #cllidepoint() checks whether the mouse click position is within the rect of the Play button if button_clicked and not stats.game_active: #The game can be restarted only by clicking the Play button area when the game is not active, so as to prevent the restart caused by delaying the Play button area during the game start_game(ai_settings, screen, stats, sb, ship, aliens, bullets) def start_game(ai_settings, screen, stats, sb, ship, aliens, bullets): '''In press Q Key or mouse click Play Button to start the game''' # Reset game settings ai_settings.initialize_dynamic_settings() # hide cursor pygame.mouse.set_visible(False) # Reset game statistics stats.reset_stats() stats.game_active = True # Reset scoreboard image sb.prep_score() sb.prep_high_score() sb.prep_level() sb.prep_ships() #Clear alien list and bullet list aliens.empty() bullets.empty() #Create a new group of aliens and center the spacecraft create_fleet(ai_settings, screen, ship, aliens) ship.center_ship() def update_screen(ai_settings, screen, stats, sb, ship, aliens, bullets, play_button): '''Update the image on the screen and switch to a new screen''' # Redraw the screen each time you cycle screen.fill(ai_settings.bg_color) #screen.fill() accepts only one argument: a color # Redraw all bullets behind ships and aliens for bullet in bullets.sprites(): #Method bullets Sprites () returns a list of all sprites in the group bullets bullet.draw_bullet() ship.blitme() #Draw the spaceship at the specified location aliens.draw(screen) #Call draw() on the group. Pygame automatically draws each element of the group. The drawing position is determined by the attribute rect of the element. Here, each alien in the group is drawn on the screen. # Show score sb.show_score() # If the game is inactive, draw the Play button if not stats.game_active: play_button.draw_button() # Make recently drawn screens visible pygame.display.flip() #The screen is constantly updated to show the new location of the element def update_bullets(ai_settings, screen, stats, sb, ship, aliens, bullets): '''Update the location of bullets and delete disappeared bullets''' # Update the location of each bullet bullets.update() #Call Update () for the group, and the group will automatically call Update () for each sprite, that is, call bullet for each bullet update() # Delete lost bullets for bullet in bullets.copy(): # Traversing a copy of a group if bullet.rect.bottom <= 0: bullets.remove(bullet) # print(len(bullets)) # Verify that the missing bullet has been deleted check_bullet_alien_collisions(ai_settings, screen, stats, sb, ship, aliens, bullets) def check_high_score(stats, sb): '''Check whether a new highest score has been born''' if stats.score > stats.high_score: #Playing this game for the first time, the current score is the highest score stats.high_score = stats.score sb.prep_high_score() def check_bullet_alien_collisions(ai_settings, screen, stats, sb, ship, aliens, bullets): '''In response to the collision between bullets and aliens''' # Delete bullets and aliens in collision collisions = pygame.sprite.groupcollide(bullets, aliens, True, True) #Whenever bullets and alien rect s overlap, Pygame deletes the bullets and aliens that collide if collisions: for aliens in collisions.values(): #Collections is a dictionary, each key is a bullet, and the corresponding value is all aliens hit by the same bullet (a list) stats.score += ai_settings.alien_points * len(aliens) #Make sure all aliens hit by each bullet are scored sb.prep_core() check_high_score(stats, sb) if len(aliens) == 0: # If the alien crowd is wiped out, delete the existing bullets and create a new group of aliens, and then increase it by one level bullets.empty() #The method empty() deletes all remaining sprites in the group ai_settings.increase_speed() #Speed up the game # Raise the level stats.level += 1 sb.prep_level() create_fleet(ai_settings, screen, ship, aliens) #Create alien groups def check_fleet_edges(ai_settings, aliens): '''When aliens reach the edge, take corresponding measures''' for alien in aliens.sprites(): if alien.check_edges(): change_fleet_direction(ai_settings, aliens) break def change_fleet_direction(ai_settings, aliens): '''Move the whole group of aliens down and change their direction''' for alien in aliens.sprites(): alien.rect.y += ai_settings.fleet_drop_speed ai_settings.fleet_direction *= -1 def ship_hit(ai_settings, stats, screen, sb, ship, aliens, bullets): '''Responding to a spaceship hit by aliens''' if stats.ships_left > 0: # Talk about ships_left minus 1 stats.ships_left -= 1 # Update scoreboard sb.prep_ships() else: stats.game_active = False pygame.mouse.set_visible(True) # When the game cursor is inactive, the Play button will be displayed # Clear alien list and bullet list aliens.empty() bullets.empty() # Create a new group of aliens and place the spacecraft in the bottom center of the screen create_fleet(ai_settings, screen, ship, aliens) ship.center_ship() # suspend sleep(0.5) def check_aliens_bottom(ai_settings, stats, screen, sb, ship, aliens, bullets): '''Check if any aliens have reached the bottom of the screen''' screen_rect = screen.get_rect() for alien in aliens.sprites(): if alien.rect.bottom >= screen_rect.bottom: # Deal with it like a ship was hit ship_hit(ai_settings, stats, screen, sb, ship, aliens, bullets) break def update_aliens(ai_settings, screen, stats, ship, sb, aliens, bullets): '''Check whether there are aliens at the edge of the screen and update the location of the whole group of aliens''' check_fleet_edges(ai_settings, aliens) aliens.update() #Call update() on the marshalling and automatically call the method update() on each alien # Detect collisions between aliens and spacecraft if pygame.sprite.spritecollideany(ship, aliens): #Accept two arguments to check whether any member of the group has collided with the wizard. If so, stop traversing the group and return the alien who has collided. Otherwise, return None ship_hit(ai_settings, stats, screen, sb, ship, aliens, bullets) # Check if aliens have reached the bottom of the screen check_aliens_bottom(ai_settings, stats, screen, sb, ship, aliens, bullets) def get_number_aliens_x(ai_settings, alien_width): '''Calculate how many aliens can be accommodated in each row''' available_space_x = ai_settings.screen_width - 2 * alien_width #Calculate the space for aliens number_aliens_x = int(available_space_x / (2 * alien_width)) #Calculate the number of aliens placed and ensure that it is an integer return number_aliens_x def get_number_rows(ai_settings, ship_height, alien_height): available_space_y = (ai_settings.screen_height - (3 * alien_height) - ship_height) #2 Aliens subtracted here_ Height is to leave a certain space between the spaceship and the aliens and give the players time to shoot the aliens number_rows = int(available_space_y / (2 * alien_height)) return number_rows def create_alien(ai_settings, screen, aliens, alien_number, row_number): '''Create an alien and place it on the current line''' # Alien spacing is alien width alien = Alien(ai_settings, screen) alien_width = alien.rect.width alien.x = alien_width + 2 * alien_width * alien_number #Determine the x coordinate of the alien alien.rect.x = alien.x alien.rect.y = alien.rect.height + 2 * alien.rect.height * row_number #Determine the y coordinate of the alien aliens.add(alien) #Add the generated alien to the group def create_fleet(ai_settings, screen, ship, aliens): '''Create alien groups''' # Create an alien and calculate how many aliens a row can hold alien = Alien(ai_settings, screen) number_aliens_x = get_number_aliens_x(ai_settings, alien.rect.width) number_rows = get_number_rows(ai_settings, ship.rect.height, alien.rect.height) #Create alien groups for row_number in range(number_rows): for alien_number in range(number_aliens_x): #Here, alien_number starts from 0, and range() also requires an integer create_alien(ai_settings, screen, aliens, alien_number, row_number)
alien_invasion.py execution code is as follows:
# -*- coding: GBK -*- import pygame # The module pygame contains the functions required to develop the game. from settings import Settings # Importing the Setting class of the Setting module from ship import Ship # Import the ship class of the ship module, which is responsible for managing most of the behavior of the ship. import game_functions as gf # Import game_functions module from pygame.sprite import Group #Used to create bullet groups from game_stats import GameStats #Import the GameStats class that tracks game statistics from button import Button #Import the Button class to create a solid rectangle with labels from scoreboard import Scoreboard #Import Scoreboard, which is used to display the current score, the highest score, level and the number of remaining ships def run_game(): # Initialize the game and create a screen object pygame.init() #Initialize the background settings so that Pygame can work correctly. ai_settings = Settings() #Create a Settings instance and use it to access the Settings screen = pygame.display.set_mode( (ai_settings.screen_width, ai_settings.screen_height)) #Call pyGame display. set_ Mode() to create a window. The argument is a ancestor, specifying the size of the game window. pygame.display.set_caption("Alien Invasion") #Set the title of the window # Create a Play Button and create a Button instance play_button = Button(ai_settings, screen, "Play") # Create an instance for storing game statistics and create a scoreboard stats = GameStats(ai_settings) sb = Scoreboard(ai_settings, screen, stats) # Create a spaceship ship = Ship(ai_settings, screen) # Create a group for storing bullets bullets = Group() # Create an alien group aliens = Group() # Create alien groups gf.create_fleet(ai_settings, screen, ship, aliens) # Start the main cycle of the game while True: # Respond to key and mouse events gf.check_events(ai_settings, screen, stats, sb, play_button, ship, aliens, bullets) if stats.game_active: # Update the ship's location ship.update() # Update the location of bullets and delete disappeared bullets gf.update_bullets(ai_settings, screen, stats, sb, ship, aliens, bullets) # Update the location of each alien gf.update_aliens(ai_settings, screen, stats, sb, ship, aliens, bullets) # The image on the new screen and switch to the new screen gf.update_screen(ai_settings, screen, stats, sb, ship, aliens, bullets, play_button) run_game()