Python project alien invasion (final) record score
In this chapter, we will end the development of the whole game project. We will add a play button to enable players to start the game by clicking or restart the game after the game is over. At the same time, we will also modify the game to speed up the pace of the game when the player level increases, and implement a scoring system. The -- snip -- in the code block represents the unchanged part of the code.
Before explaining this section, we first made the following modifications to make the game layout more reasonable:
# settings.py self.ship_speed = 1.5 # Set the initial value of spacecraft speed self.bullet_speed = 3 # Bullet speed self.alien_speed = 0.5 # Aliens move at a speed of 0.5
Modified the speed of spacecraft, bullets and aliens.
# game_function.py def get_number_rows(ai_settings, ship_height, alien_height): """Calculate how many lines the screen can hold""" # Calculate how much space is left on the screen available_space_y = ai_settings.screen_height - 4 * alien_height - ship_height # How many lines are there on the calculation screen number_rows = int(available_space_y / (2 * alien_height)) return number_rows
Modified the formula to calculate how much space is left on the screen, and changed the height of three aliens to four.
Add Play key
In this chapter, we will add a play button, which will appear before the beginning of the game and again after the end of the game, so that players can restart the game.
Make the game inactive
Currently, the game is running alien_invasion.py starts. Next, we need to make the game inactive. Only when we click the Play button can we enter the active state and start the game. Therefore, we need to modify the game_ stats. Parameters of Py:
class GameStats: """Track game statistics""" def __init__(self, ai_settings): self.ai_settings = ai_settings self.reset_stats() self.game_active = False # The game has just started and is inactive
Create Button class
Since Pygame has no built-in method to create buttons, we need to create a Button class to create a solid rectangle with labels. We can use these codes to create any Button. First, we create a Python file and name it Button py:
# button.py import pygame.ftfont # The module can render text to the screen class Button: # message is the text we want to display in the button def __init__(self, ai_settings, screen, message): """Initialize button properties""" self.screen = screen self.screen_rect = screen.get_rect() # Set the size and other properties of the button self.width, self.height = 200, 50 self.button_color = (0, 255, 0) # The button is set to green self.text_color = (255, 255, 255) # The text content is set to white self.font = pygame.font.SysFont(None, 48) # None indicates the default font and 48 indicates the font size # Create a rect object for the button and center it self.rect = pygame.Rect(0, 0, self.width, self.height) self.rect.center = self.screen_rect.center # Create a label for the button self.prep_msg(message) # Render the message as an image and center it in the button
The relevant interpretation of the emerging code is shown in the notes, where prep_ The code of MSG () is as follows. We use this function to render text as an image:
# button.py def prep_msg(self, message): """take message Render as an image and center it in the button""" self.msg_image = self.font.render(message, True, self.text_color, self.button_color) # Convert text to image self.msg_image_rect = self.msg_image.get_rect() self.msg_image_rect.center = self.rect.center
Method prep_msg(), receive the argument self and the text message to be rendered as an image. Call method font Render () converts the text stored in message into an image. This method receives a Boolean argument that specifies whether anti aliasing (anti aliasing makes the text edge smoother) is turned on or off.
Finally, we create the method draw_button() method, which can be called to display the button on the screen.
# button.py def draw_button(self): """Draw a button before you draw text""" self.screen.fill(self.button_color, self.rect) # Draw button self.screen.blit(self.msg_image, self.msg_image_rect) # Draw text
The fill() method fills the block with the specified color at the specified position
The blit() method draws the image at the specified place.
Draw button on screen
We use the Button class to create a Play Button. Since we only need one Play Button, we directly create a Play Button in alien_ invasion. Create it in py:
# alien_invasion.py from button import Button --snip-- play_button = Button(ai_settings, screen, "Play") # Create an instance of the Button class --snip-- gf.update_screen(ai_settings, screen, ship, aliens, bullets, play_button) run_geme()
Here, we create an instance of the Button class, and then pass the instance to update_screen(), so that the Button can be displayed when the screen is updated. Next, we modify update_screen() function:
# game_function.py def update_screen(ai_settings, screen, stats, ship, aliens, bullets, play_button): """Update the image on the screen and switch to a new screen""" screen.fill(ai_settings.bg_color) # Fills the screen with the specified color for bullet in bullets: bullet.draw_bullet() ship.blitme() # Display the spacecraft on the screen aliens.draw(screen) # Let aliens appear on the screen if not stats.game_active: # Print the start button if the game is inactive play_button.draw_button() pygame.display.flip() # Displays the most recently drawn screen
In order to display the Play button on all other screen elements, we draw the button after drawing all other elements. Now we will see a Play button in the center of the screen after running the main function.
Use the button to start the game
Next, we need to modify the check_evernts() code, a new function check has been created_ play_ button():
# game_function.py def check_events(ai_settings, screen, stats, play_button, ship, bullets): """Respond to keyboard and mouse events""" for event in pygame.event.get(): if event.type == pygame.QUIT: # If the type of event is exit, it is equivalent to mouse click × sys.exit() elif event.type == pygame.KEYDOWN: # Determine whether a key is pressed check_keydown_events(event, ai_settings, screen, ship, bullets) elif event.type == pygame.KEYUP: # Judge whether the key is released check_keyup_events(event, ship) elif event.type == pygame.MOUSEBUTTONDOWN: # Determine whether the mouse is pressed mouse_x, mouse_y = pygame.mouse.get_pos() # Returns the coordinates of the pressed point check_play_button(stats, play_button, mouse_x, mouse_y) def check_play_button(stats, play_button, mouse_x, mouse_y): """Click on the player Play Start the game after""" if play_button.rect.collidepoint(mouse_x, mouse_y): # Judge whether the position of the mouse click is within the key stats.game_active = True
No matter where the player clicks the screen, Pygame will detect a mousebuttown event, but we only want the game to respond when the player clicks the Play button. For this reason, we use Pygame mouse. get_ POS () function, which returns a tuple containing the coordinates of the click position, and then we pass the value to the function check_play_button() determines whether the clicked position is in the button. If so, start the game, otherwise nothing will happen.
Next, we modify check in the main function_ Events () function and pass the new arguments.
# alien_invasion.py gf.check_events(ai_settings, screen, stats, play_button, ship, bullets)
Reset game
The code written above only deals with the situation when the player clicks the Play button for the first time, but does not deal with the situation at the end of the game, because the conditions leading to the end of the game are not reset. Next, we set up to reset the game every time the player clicks the Play button, including statistics, delete existing aliens, bullets, and create a new group to center the ship.
# game_function.py def check_play_button(ai_settings, screen, stats, play_button, ship, aliens, bullets, mouse_x, mouse_y): """Click on the player Play Start the game after""" if play_button.rect.collidepoint(mouse_x, mouse_y): # Judge whether the position of the mouse click is within the key # Reset game statistics stats.rest_stats() stats.game_active = True # Clear alien and bullet list aliens.empty() bullets.empty() # Create a new group of aliens and center it create_fleet(ai_settings, screen, ship, aliens) ship.center_ship()
Here we update the check_play_button() function, where we pass in new parameters. After clicking, we provide players with three new spaceships, delete existing aliens and bullet groups, create a new group, and finally center the spaceship.
Next, we need to modify the check_ The events () part of the code and make it pass in the parameters correctly.
# game_function.py def check_events(ai_settings, screen, stats, play_button, ship, aliens, bullets): """Respond to keyboard and mouse events""" for event in pygame.event.get(): if event.type == pygame.QUIT: # If the type of event is exit, it is equivalent to mouse click × sys.exit() elif event.type == pygame.KEYDOWN: # Determine whether a key is pressed check_keydown_events(event, ai_settings, screen, ship, bullets) elif event.type == pygame.KEYUP: # Judge whether the key is released check_keyup_events(event, ship) elif event.type == pygame.MOUSEBUTTONDOWN: # Determine whether the mouse is pressed mouse_x, mouse_y = pygame.mouse.get_pos() # Returns the coordinates of the pressed point check_play_button(ai_settings, screen, stats, play_button, ship, aliens, bullets, mouse_x, mouse_y)
Meanwhile, alien_ invasion. The code of Py also needs to be modified:
# alien_invasion.py gf.check_events(ai_settings, screen, stats, play_button, ship, aliens, bullets)
Now when we click the Play button, the game will be reset correctly. We can Play it as many times as we want.
Switch the Play button to inactive
At present, the Play button has the following problems: even if the Play button is not visible, the game will restart when the player clicks the original area. Next, we can solve this problem by setting the Play button to be effective when the game is inactive
def check_play_button(ai_settings, screen, stats, play_button, ship, aliens, bullets, mouse_x, mouse_y): """Click on the player Play Start the game after""" # Judge whether the position of the mouse click is within the key and whether the game state is active at this time if play_button.rect.collidepoint(mouse_x, mouse_y) and not stats.game_active: # Reset game statistics stats.reset_stats() stats.game_active = True # Clear alien and bullet list aliens.empty() bullets.empty() # Create a new group of aliens and center it create_fleet(ai_settings, screen, ship, aliens) ship.center_ship()
Hide game cursor
In order for the player to start the game, we need to make the cursor visible, but next we want the cursor to be invisible when the game is inactive:
# game_function.py def check_play_button(ai_settings, screen, stats, play_button, ship, aliens, bullets, mouse_x, mouse_y): """Click on the player Play Start the game after""" # Judge whether the position of the mouse click is within the key and whether the game state is active at this time if play_button.rect.collidepoint(mouse_x, mouse_y) and not stats.game_active: # hide cursor pygame.mouse.set_visible(False) # Reset game statistics stats.reset_stats() stats.game_active = True # Clear alien and bullet list aliens.empty() bullets.empty() # Create a new group of aliens and center it create_fleet(ai_settings, screen, ship, aliens) ship.center_ship()
Through set_ The parameter in the visible() function is False. We can hide the mouse at the beginning of the game. Next, we need to re display the cursor after the game.
# game_function.py def ship_hit(ai_settings, stats, screen, ship, aliens, bullets): """Responding to a spaceship hit by aliens""" if stats.ships_left > 0: # Reduce the number of ships by one stats.ships_left -= 1 # Clear the list of bullets and aliens aliens.empty() bullets.empty() # Create a new group of aliens and put the spacecraft in the center of the screen create_fleet(ai_settings, screen, ship, aliens) # Create new aliens ship.center_ship() # Move the spacecraft to the center of the screen # suspend sleep(0.5) else: stats.game_active = False pygame.mouse.set_visible(True)
In the last line above, we are in set_ Pass in the parameter True in the visible() function to make the mouse appear again when the game is inactive, so as to operate with the player.
Continuously improve the level as the game progresses
At present, after the whole group of aliens are eliminated, the difficulty of the game has not changed. Next, we will increase the difficulty of the game: whenever the player eliminates the foreign person on the screen, speed up the rhythm of the game and make the game more difficult.
Modify speed settings
First, we reorganize the Settings class and divide the game Settings into static and dynamic parts. Static Settings refer to Settings that will not change with the progress of the game.
# settings.py class Settings: """Store all classes related to alien invasion""" def __init__(self): """Initialize game static settings""" # screen setting self.screen_width = 1200 # Set window width self.screen_height = 700 # Set window height self.bg_color = (230, 230, 230) # Set background color # Spacecraft setup self.ship_limit = 3 # Set the maximum number of ships for players # Bullet setting self.bullet_width = 3 # The width of the bullet self.bullet_height = 15 # Bullet height self.bullet_color = (60, 60, 60) # Bullet color self.bullets_allowed = 3 # Limit the number of bullets that do not disappear to 3 # Alien settings self.fleet_drop_speed = 10 # The speed at which aliens move down # What kind of speed to accelerate the pace of the game self.speed_up = 1.1 self.initialize_dynamic_speed() def initialize_dynamic_speed(self): """The amount of dynamic change as the game progresses""" self.ship_speed = 1.5 # Sets the initial value of the speed self.bullet_speed = 3 # Bullet speed self.alien_speed = 1 # Aliens move at a speed of 0.5 # fleet_ When direction is 1, it means to move right, and when direction is - 1, it means to move left self.fleet_direction = 1
We are__ init__ () initializes the static setting and adds the setting speed_up is used to control the acceleration of the game rhythm. At the same time, we put some quantities that will change with the progress of the game in the function initialize_ dynamic_ In speed (), we reset these variables whenever the game starts again.
Next, we define increase in it_ Speed() function to increase speed:
# settings.py def increase_speed(self): """Speed up""" self.ship_speed *= self.speed_up self.bullet_speed *= self.speed_up self.alien_speed *= self.speed_up
In this function, we increase the speed of spacecraft, bullets and aliens to the last speed every time_ When we finish killing a group of aliens, we will call this function to speed up the progress of the game, and then create a group of new Aliens:
def update_bullets(ai_settings, screen, ship, aliens, bullets): """Update the location of bullets and delete bullets that have disappeared""" bullets.update() # The number of lists or groups should not be modified in the for loop, which will lead to the loss of traversal for bullet in bullets.copy(): if bullet.rect.bottom <= 0: bullets.remove(bullet) check_bullet_alien_collisions(ai_settings, screen, ship, aliens, bullets)
Reset speed at the end of the game
Whenever players start a new game, we need to restore the changed settings to their original values.
# game_function.py def check_play_button(ai_settings, screen, stats, play_button, ship, aliens, bullets, mouse_x, mouse_y): """Click on the player Play Start a new game after""" # Judge whether the position of the mouse click is within the key and whether the game state is active at this time if play_button.rect.collidepoint(mouse_x, mouse_y) and not stats.game_active: # Reset game speed settings ai_settings.initialize_dynamic_speed() # hide cursor pygame.mouse.set_visible(False) # Reset game statistics stats.reset_stats() stats.game_active = True # Clear alien and bullet list aliens.empty() bullets.empty() # Create a new group of aliens and center it create_fleet(ai_settings, screen, ship, aliens) ship.center_ship()
Now the game function of the game is basically developed. At present, we can design aliens through spacecraft and gradually increase the difficulty of the game. Next, we will develop a scoring system.
Score record
Note down that we will implement a scoring system to track players' scores in real time and display the highest score, current level and the number of remaining ships.
Because the score is a statistical information of the game, we add a score attribute in the GameStats class:
# gamestats.py def reset_stats(self): """Initialize information that may change during game operation""" # Count the number of ships remaining in the game self.ships_left = self.ai_settings.ship_limit self.score = 0 # Count game scores
In order to reset the score at the beginning of the game every time, we are reset_ Reset score information in stats() function.
Show score
In order to display the score on the screen, we first create a new class ScoreBoard. At present, this class only displays scores, but later we also use it to display the highest score, level and the number of remaining ships.
# scoreboard.py import pygame.ftfont class Scoreboard: """Class that displays score information""" def __init__(self, ai_settings, screen, stats): """Initialize the attributes involved in displaying scores""" self.screen = screen self.screen_rect = screen.get_rect() self.ai_settings = ai_settings self.stats = stats # Font setting for displaying score information self.text_color = (30, 30, 30) self.font = pygame.font.SysFont(None, 48) # Prepare initial score image self.prep_score()
Because we need to display text on the screen, we need to import pyGame Ftfont, next we will use the method prep_ Convert text to image in score():
# scoreboard.py def prep_score(self): """Render scores as images""" score_str = str(self.stats.score) self.score_image = self.font.render(score_str, True, self.text_color, self.ai_settings.bg_color) # Displays the score in the upper right corner self.score_rect = self.score_image.get_rect() self.score_rect.rigtht = self.screen_rect.right - 20 self.score_rect.top = 20
In the above method, we first convert the digital value into a string, and then pass the string to the render() function to render the image. In order to display the score more clearly, we pass the screen background color and text color to render().
Here, we put the score window in the upper right corner of the screen and extend it to the left when the score increases and the number widens.
Next, we create the method show_score() is used to better render the image:
# scoreboard.py def show_score(self): """Show score""" self.screen.blit(self.score_image, self.score_rect)
This method displays the score image to the specified position.
Create scoreboard
In order to show the score, we are in alien_invasion.py to create an instance of ScoreBoard:
# alien_invasion.py --snip-- from scoreboard import Scoreboard --snip-- stats = GameStats(ai_settings) sb = Scoreboard(ai_settings, screen, stats) --snip-- gf.update_screen(ai_settings, screen, stats, sb, ship, aliens, bullets, play_button) run_game()
Next, we call the print scorecard function in the screen update function and pass the corresponding parameters:
# game_funcrion.py 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""" screen.fill(ai_settings.bg_color) # Fills the screen with the specified color for bullet in bullets: bullet.draw_bullet() ship.blitme() # Display the spacecraft on the screen aliens.draw(screen) # Let aliens appear on the screen sb.show_score() # Print scoring information if not stats.game_active: # Print the start button if the game is inactive play_button.draw_button() pygame.display.flip() # Displays the most recently drawn screen
Score points when aliens are eliminated
In order to display the score in real time on the screen, we will update stats whenever an alien is hit Score, and then call prep_score() updates the score image, but before that, we need to indicate how many points players can get for each alien shot down:
# settings.py def initialize_dynamic_speed(self): """The amount of dynamic change as the game progresses""" self.ship_speed = 1.5 # Set the initial value of spacecraft speed self.bullet_speed = 3 # Bullet speed self.alien_speed = 0.5 # Aliens move at a speed of 0.5 self.alien_point = 50 # Points per alien defeated # fleet_ When direction is 1, it means to move right, and when direction is - 1, it means to move left self.fleet_direction = 1
As the game goes on, we will increase the points of each alien value. In order to ensure that this value will be reset before starting a new game, we will initialize_ dynamic_ Set it in speed().
Next, check_ bullet_ alien_ In collections (), whenever an alien is shot down, the score will be updated
# game_function.py def check_bullet_alien_collisions(ai_settings, screen, stats, sb, ship, aliens, bullets): """Respond to the collision between bullets and aliens, and generate a new group of aliens after all aliens die""" # Detect whether a bullet hit the alien. If so, delete the bullet and alien collisions = pygame.sprite.groupcollide(bullets, aliens, True, True) if collisions: # Increase score when hitting aliens stats.score += ai_settings.alien_point sb.prep_score() if len(aliens) == 0: # If all aliens are eliminated, delete the existing bullets and regenerate aliens bullets.empty() ai_settings.increase_speed() create_fleet(ai_settings, screen, ship, aliens)
Here we update the check_ bullet_ alien_ The definition of collections () includes the formal parameters stats and sb. When the bullet hits an alien, Pygame will return a dictionary. We check whether the dictionary exists. If so, we will increase the score of an alien, and then we use prep_score() to create an image showing the latest score.
Next, we modify update_bullets(), ensuring that the correct arguments are passed between functions
# game_function.py def update_bullets(ai_settings, screen, stats, sb, ship, aliens, bullets): """Update the location of bullets and delete bullets that have disappeared""" bullets.update() # The number of lists or groups should not be modified in the for loop, which will lead to the loss of traversal for bullet in bullets.copy(): if bullet.rect.bottom <= 0: bullets.remove(bullet) check_bullet_alien_collisions(ai_settings, screen, stats, sb, ship, aliens, bullets)
At the same time, we need to modify the code in the main loop that calls the functions mentioned above.
while True: gf.check_events(ai_settings, screen, stats, play_button, ship, aliens, bullets) if stats.game_active: ship.update() gf.update_bullets(ai_settings, screen, stats, sb, ship, aliens, bullets) gf.update_aliens(ai_settings, stats, screen, ship, aliens, bullets) gf.update_screen(ai_settings, screen, stats, sb, ship, aliens, bullets, play_button)
Every alien's point will be included in the point of elimination
At present, our code may miss some eliminated aliens. For example, two bullets hit aliens in a cycle, or because the bullets are wider and hit multiple aliens at the same time, players will only get one alien score at this time. In order to fix this problem, we adjust the way of collision detection:
# game_function.py def check_bullet_alien_collisions(ai_settings, screen, stats, sb, ship, aliens, bullets): """After all aliens collide with the new alien group, all aliens will respond""" # Detect whether a bullet hit the alien. If so, delete the bullet and alien collisions = pygame.sprite.groupcollide(bullets, aliens, True, True) if collisions: # Increase score when hitting aliens for aliens in collisions.values(): stats.score += ai_settings.alien_point * len(aliens) sb.prep_score() if len(aliens) == 0: # If all aliens are eliminated, delete the existing bullets and regenerate aliens bullets.empty() ai_settings.increase_speed() create_fleet(ai_settings, screen, ship, aliens)
In check_ bullet_ alien_ In collections (), each bullet colliding with aliens is a key in the dictionary, and the values related to bullets are a list. We traverse the list of values in the dictionary to ensure that each eliminated alien is included in the score.
Increase points
Since it becomes more difficult for players to destroy a group of aliens, the points of aliens should be higher at a higher level:
# settings.py class Settings: """Store all classes related to alien invasion""" def __init__(self): --snip-- self.speed_up = 1.1 # What kind of speed to accelerate the pace of the game self.score_scale = 1.5 # Speed up scores --snip def increase_speed(self): """Speed up""" self.ship_speed *= self.speed_up self.bullet_speed *= self.speed_up self.alien_speed *= self.speed_up self.alien_point = int(self.alien_point * self.score_scale) # print(self.alien_point) # Print and display the score of the current alien
Here, we define that the fraction increases at a rate of 1.5 times. In order to make the calculated points an integer, we use the function int().
The last print statement is to enable us to see the score of the current alien in the terminal window every time we raise a level. At the last run time, we can comment out this line of code.
Round the score
Many shooting games will display scores as multiples of 10, so our small game will also follow this principle, and we will also set the format of numbers and add commas to larger numbers to divide the thousandths, so we are in prep_ Add the following code to the score () method
# scoreboard.py def prep_score(self): """Render scores as images""" rounded_score = int(round(self.stats.score, -1)) score_str = "{:,}".format(rounded_score) self.score_image = self.font.render(score_str, True, self.text_color, self.ai_settings.bg_color)
The function round() is used to exact the decimal to the number of digits after the decimal point, but if a negative number is passed, it will be accurate to an integer multiple of 101001000, etc. At the same time, a string formatting instruction is used in the next line, which allows Python to insert a comma when converting a value into a string.
Highest score
Next, we track and record the highest score of the game:
# game_function.py def __init__(self, ai_settings): self.ai_settings = ai_settings self.reset_stats() self.game_active = False # The game has just started and is active self.high_score = 0 # The highest score should not be reset at any time
We first create a new attribute high_score, since the highest score will not be reset under any circumstances, we__ init__ Function.
Next, we are at scoreboard Py adds a function to display the highest score and distinguish it from the current score.
# scoreboard.py def __init__(self, ai_settings, screen, stats): """Initialize the attributes involved in displaying scores""" --snip-- # Prepare initial score image self.prep_score() self.prep_high_score()
Next, we are in prep_ high_ The score () method renders the highest score as an image and uses the same output format as the current score
# scoreboard.py 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 in the 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 = 20
The main function of this method is to place the highest score in the top center of the screen, and adopts the same rounding method as displaying the current score, which will not be repeated here.
Next, we're on show_ This method is invoked in the score () method to display the highest score on the screen.
# scoreboard.py def show_score(self): """Show score""" self.screen.blit(self.score_image, self.score_rect) # Displays the current score self.screen.blit(self.high_score_image, self.high_score_rect) # Show highest score
In order to check whether there is a new highest score, we need to be in game_ function. Add a new function check in PY_ high_ score()
# game_function def check_high_score(stats, sb): """Check whether the highest score is born""" if stats.score > stats.high_score: stats.high_score = stats.score sb.prep_high_score()
In this function, we compare the current score with the highest score. Once the current score exceeds the highest score, I Emei you will modify the value of the highest score. To do this, we need to call this function every time an alien is destroyed:
def check_bullet_alien_collisions(ai_settings, screen, stats, sb, ship, aliens, bullets): """Respond to the collision between bullets and aliens, and generate a new group of aliens after all aliens die""" # Detect whether a bullet hit the alien. If so, delete the bullet and alien collisions = pygame.sprite.groupcollide(bullets, aliens, True, True) if collisions: # Increase score when hitting aliens for aliens in collisions.values(): stats.score += ai_settings.alien_point * len(aliens) sb.prep_score() check_high_score(stats, sb) if len(aliens) == 0: # If all aliens are eliminated, delete the existing bullets and regenerate aliens bullets.empty() ai_settings.increase_speed() create_fleet(ai_settings, screen, ship, aliens)
When the dictionary exists, we update the score according to the number of aliens eliminated, and then we call check_high_score() function to determine whether the highest score needs to be updated.
Display level
In order to display the player's level in the game, we need to add an attribute representing the current level to the GameStats class. At the same time, in order to cut thin, we can reset the level every time we start a new game_ Initialize this property in the stats() function.
# game_stats.py def reset_stats(self): """Initialize information that may change during game operation""" # Count the number of ships remaining in the game self.ships_left = self.ai_settings.ship_limit self.score = 0 # Count game scores self.level = 1 # Count the level information of the game
Next, in order to display the current level below the current score, we__ init__ A new method called prep_ is invoked in the method. Level () is used to render the game level as an image.
# scoreboard.py class Scoreboard: """Class that displays score information""" def __init__(self, ai_settings, screen, stats): """Initialize the attributes involved in displaying scores""" --snip-- # Prepare to display the image of the current score and the highest score self.prep_score() self.prep_high_score() self.prep_level()
Method prep_ The code of level() is as follows:
# scoreboard.py def prep_level(self): """Convert levels to images""" self.level_image = self.font.render(str(self.stats.level), True, self.text_color, self.ai_settings.bg_color) # Put the grade 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
This method renders the value of the level as an image and places the image below the current score.
Next, we update show_score() method to print the value of the grade:
# scoreboard.py def show_score(self): """Show score""" self.screen.blit(self.score_image, self.score_rect) # Displays the current score self.screen.blit(self.high_score_image, self.high_score_rect) # Show highest score self.screen.blit(self.level_image, self.level_rect)
Next, we need to update the following functions to upgrade the current level one level every time we eliminate a group of Aliens:
# game-function def check_bullet_alien_collisions(ai_settings, screen, stats, sb, ship, aliens, bullets): """Respond to the collision between bullets and aliens, and generate a new group of aliens after all aliens die""" # Detect whether a bullet hit the alien. If so, delete the bullet and alien collisions = pygame.sprite.groupcollide(bullets, aliens, True, True) if collisions: # Increase score when hitting aliens for aliens in collisions.values(): stats.score += ai_settings.alien_point * len(aliens) sb.prep_score() check_high_score(stats, sb) if len(aliens) == 0: # If all aliens are eliminated, delete the existing bullets and regenerate aliens bullets.empty() ai_settings.increase_speed() # Raise the level stats.level += 1 sb.prep_level() create_fleet(ai_settings, screen, ship, aliens)
In the above function, if we wipe out a group of aliens, we will add 1 to the value of level and call prep_level() method, so that the level can be displayed normally.
At the same time, in order to update the score and level image when we restart the game, we need to modify the code after we click the Play button:
# game_function.py def check_play_button(ai_settings, screen, stats, sb, play_button, ship, aliens, bullets, mouse_x, mouse_y): """Click on the player Play Start a new game after""" # Judge whether the position of the mouse click is within the key and whether the game state is active at this time if play_button.rect.collidepoint(mouse_x, mouse_y) and not stats.game_active: # Reset game settings ai_settings.initialize_dynamic_speed() # 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() # Clear alien and bullet list aliens.empty() bullets.empty() # Create a new group of aliens and center it create_fleet(ai_settings, screen, ship, aliens) ship.center_ship()
In the above code, we reset the scoreboard image after resetting the statistical information of the game, because we need to call scoreboard Py, so we need to pass in the instance of the module in the parameter.
At the same time, we need to modify the check_ Formal parameter of events(), to which an instance of scoreboard module is passed:
# game_function.py def check_events(ai_settings, screen, stats, sb, play_button, ship, aliens, bullets): """Respond to keyboard and mouse events""" for event in pygame.event.get(): if event.type == pygame.QUIT: # If the type of event is exit, it is equivalent to mouse click × sys.exit() elif event.type == pygame.KEYDOWN: # Determine whether a key is pressed check_keydown_events(event, ai_settings, screen, ship, bullets) elif event.type == pygame.KEYUP: # Judge whether the key is released check_keyup_events(event, ship) elif event.type == pygame.MOUSEBUTTONDOWN: # Determine whether the mouse is pressed mouse_x, mouse_y = pygame.mouse.get_pos() # Returns the coordinates of the pressed point check_play_button(ai_settings, screen, stats, sb, play_button, ship, aliens, bullets, mouse_x, mouse_y)
After that, we need to modify the call to check_ in the main function. Formal parameters passed in the events () section
# alien.invasion.py while True: gf.check_events(ai_settings, screen, stats, sb, play_button, ship, aliens, bullets) if stats.game_active: ship.update() gf.update_bullets(ai_settings, screen, stats, sb, ship, aliens, bullets) gf.update_aliens(ai_settings, stats, screen, ship, aliens, bullets) gf.update_screen(ai_settings, screen, stats, sb, ship, aliens, bullets, play_button)
Displays the number of ships remaining
Finally, let's show how many ships the player has left, but here we'll use pictures instead of numbers. To this end, we draw the number of spaceships in the upper left corner of the screen.
First, we let the Ship class inherit Sprite so that we can correctly create the Ship group.
# ship.py class Ship(Sprite): def __init__(self, ai_settings, screen): """Initialize the spacecraft and set its initial position""" super(Ship, self).__init__() --snip--
First of all, we need to create and update a module in ScoreBoard for our initialization
# scoreboard.py import pygame.ftfont from pygame.sprite import Group from ship import Ship class Scoreboard: """Class that displays score information""" def __init__(self, ai_settings, screen, stats): """Initialize the attributes involved in displaying scores""" --snip-- # Prepare to display the image of the current score and the highest score self.prep_score() self.prep_high_score() self.prep_level() self.prep_ships()
Next, we are in prep_ Create a ship group in the ship () method and use this method to show how many ships are left.
# scoreboard.py 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_settings, self.screen) ship.rect.x = 10 + ship_number * ship.rect.width self.rect.y = 10 self.ships.add(ship)
In this method, we create an empty group to store instances of ships. In order to fill this group, we cycle the corresponding times according to how many ships the player has. In this method, we create a spaceship, reset its coordinates, and then add it to the group.
Next we need to start drawing the spacecraft:
# scoreboard.py def show_score(self): """Show score""" self.screen.blit(self.score_image, self.score_rect) # Displays the current score self.screen.blit(self.high_score_image, self.high_score_rect) # Show highest score self.screen.blit(self.level_image, self.level_rect) # Drawing spacecraft self.ships.draw(self.screen)
In order to let the player know how many ships he has at the beginning of the game, we call the above function at the beginning of the game
# game_function.py def check_play_button(ai_settings, screen, stats, sb, play_button, ship, aliens, bullets, mouse_x, mouse_y): """Click on the player Play Start a new game after""" --snip-- stats.game_active = True # Reset scoreboard image sb.prep_score() # Reset current score sb.prep_high_score() # Reset maximum score sb.prep_level() # Reset game level sb.prep_ships() # Reset available ships
Next, we need to call prep when the spacecraft is hit by aliens_ Ships() method
# game_function.py def ship_hit(ai_settings, stats, sb, screen, ship, aliens, bullets): """Responding to a spaceship hit by aliens""" if stats.ships_left > 0: stats.ships_left -= 1 # Reduce the number of ships by one sb.prep_ships() # Update scoreboard # Clear the list of bullets and aliens aliens.empty() bullets.empty() # Create a new group of aliens and put the spacecraft in the center of the screen create_fleet(ai_settings, screen, ship, aliens) # Create new aliens ship.center_ship() # Move the spacecraft to the center of the screen # suspend sleep(0.5) else: stats.game_active = False pygame.mouse.set_visible(True)
Here, we pass in the instance sb of the module scoreboard and call prep when the number of spacecraft decreases_ Ships() method
At the same time, we need to modify the following functions and the corresponding function calls to ensure that the parameters are passed correctly
def check_aliens_bottom(ai_settings, stats, sb, screen, ship, aliens, bullets): """Check if aliens have reached the bottom of the screen""" screen_rect = screen.get_rect() # Read the matrix information of the screen for alien in aliens: # If the coordinates of the alien's bottom matrix are larger than the screen, the collision response is performed if alien.rect.bottom >= screen_rect.bottom: ship_hit(ai_settings, stats, sb, screen, ship, aliens, bullets) break def update_aliens(ai_settings, stats, sb, screen, ship, aliens, bullets): """Update the location of Aliens""" check_fleet_edges(ai_settings, aliens) aliens.update() # Detect the collision between aliens and spacecraft if pygame.sprite.spritecollideany(ship, aliens): ship_hit(ai_settings, stats, sb, screen, ship, aliens, bullets) check_aliens_bottom(ai_settings, stats, sb, screen, ship, aliens, bullets)
Finally, we modify the code of the calling part in the main function and pass the argument sb to it
# alien.invasion.py while True: gf.check_events(ai_settings, screen, stats, sb, play_button, ship, aliens, bullets) if stats.game_active: ship.update() gf.update_bullets(ai_settings, screen, stats, sb, ship, aliens, bullets) gf.update_aliens(ai_settings, stats, sb,screen, ship, aliens, bullets) gf.update_screen(ai_settings, screen, stats, sb, ship, aliens, bullets, play_button)
The figure below shows the complete game scoring system, and the number of ships remaining is indicated in the upper left corner
summary
This is the end of the study of alien invasion in the project. We have learned in this project, such as hot drawing images on Pygame, how to respond to mouse and keyboard keys, creating visual buttons, etc., but there are still many imperfections in this project. For example, the highest score will be restored to 0 every time the project is re run, without other additional functions, For example, aliens can also launch bullets and then control the spacecraft to avoid. In the follow-up process, if there is a chance, the project will be optimized. Next, I mainly study the knowledge related to chart drawing and image processing.
All codes
The following is the code that can run successfully in the environment mentioned at the beginning as a reference, including a total of nine modules
alien_invasion.py
# Main module, alien_invasion.py import pygame # It contains the functions required for game development from settings import Settings from ship import Ship import game_function as gf from pygame.sprite import Group from game_stats import GameStats from button import Button from scoreboard import Scoreboard def run_game(): """Initialize the game and create a screen object""" pygame.init() # Initialize and check whether the toolkit is complete ai_settings = Settings() screen = pygame.display.set_mode( (ai_settings.screen_width, ai_settings.screen_height)) # Create a window with a size of 800 * 600 pygame.display.set_caption("Alien invasion") # Set screen name play_button = Button(ai_settings, screen, "Play") stats = GameStats(ai_settings) sb = Scoreboard(ai_settings, screen, stats) ship = Ship(ai_settings, screen) # Create a spaceship bullets = Group() # Create a group to store bullets aliens = Group() # Create an alien group gf.create_fleet(ai_settings, screen, ship, aliens) # Create alien groups # Start the main cycle of the game while True: gf.check_events(ai_settings, screen, stats, sb, play_button, ship, aliens, bullets) if stats.game_active: ship.update() gf.update_bullets(ai_settings, screen, stats, sb, ship, aliens, bullets) gf.update_aliens(ai_settings, stats, sb,screen, ship, aliens, bullets) gf.update_screen(ai_settings, screen, stats, sb, ship, aliens, bullets, play_button) run_game() # Run program
ship.py
# Initialize the relevant class of the spacecraft, ship py import pygame from pygame.sprite import Sprite class Ship(Sprite): def __init__(self, ai_settings, screen): """Initialize the spacecraft and set its initial position""" super(Ship, self).__init__() self.screen = screen self.moving_right = False # Can I move the sign to the right self.moving_left = False # Can I move the sign to the left self.ai_settings = ai_settings # Load the ship image and obtain its circumscribed rectangle self.image = pygame.image.load("images/ship.bmp") self.rect = self.image.get_rect() # Get the size attribute of the image and save it self.screen_rect = screen.get_rect() # Get the size attribute of the screen and save it # Put each new ship in the center of the bottom self.rect.centerx = self.screen_rect.centerx # Obtain the midpoint data of the x-axis of the screen and assign it to rect self.rect.bottom = self.screen_rect.bottom # Get the bottom position data of the screen and assign it to rect # Store decimals in the attribute center of the spacecraft self.center = float(self.rect.centerx) # A new decimal storage property def blitme(self): """Draw the spaceship at the specified location""" self.screen.blit(self.image, self.rect) def update(self): """Check the status of the flag, if the flag is True Just move the ship""" # Update the center value of the spacecraft instead of the rect value if self.moving_right and self.rect.right < self.screen_rect.right: self.center += self.ai_settings.ship_speed if self.moving_left and self.rect.left > 0: self.center -= self.ai_settings.ship_speed # According to self The value of center updates self Value of centerx self.rect.centerx = self.center def center_ship(self): """Center the ship on the screen""" self.center = self.screen_rect.centerx
game_function.py
# Functions about various functions of the game, game_fuction.py import sys # Use the sys module to exit the game import pygame # It contains the functions required for game development from bullet import Bullet from alien import Alien from time import sleep def check_keydown_events(event, ai_settings, screen, ship, bullets): """Operate in response to the key""" if event.key == pygame.K_RIGHT: # Determine whether the right arrow is pressed ship.moving_right = True elif event.key == pygame.K_LEFT: # Determine whether the left arrow is pressed ship.moving_left = True elif event.key == pygame.K_SPACE: # Determine whether the space is pressed fire_bullet(ai_settings, screen, ship, bullets) elif event.key == pygame.K_q: # Judge whether Q is pressed. If Q is pressed, quit the game sys.exit() def check_keyup_events(event, ship): """Response release key""" if event.key == pygame.K_RIGHT: # Right arrow when judging the released ship.moving_right = False elif event.key == pygame.K_LEFT: # Judge whether there is an arrow loosened ship.moving_left = False def check_events(ai_settings, screen, stats, sb, play_button, ship, aliens, bullets): """Respond to keyboard and mouse events""" for event in pygame.event.get(): if event.type == pygame.QUIT: # If the type of event is exit, it is equivalent to mouse click × sys.exit() elif event.type == pygame.KEYDOWN: # Determine whether a key is pressed check_keydown_events(event, ai_settings, screen, ship, bullets) elif event.type == pygame.KEYUP: # Judge whether the key is released check_keyup_events(event, ship) elif event.type == pygame.MOUSEBUTTONDOWN: # Determine whether the mouse is pressed mouse_x, mouse_y = pygame.mouse.get_pos() # Returns the coordinates of the pressed point 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 Start a new game after""" # Judge whether the position of the mouse click is within the key and whether the game state is active at this time if play_button.rect.collidepoint(mouse_x, mouse_y) and not stats.game_active: # Reset game settings ai_settings.initialize_dynamic_speed() # hide cursor pygame.mouse.set_visible(False) # Reset game statistics stats.reset_stats() stats.game_active = True # Reset scoreboard image sb.prep_score() # Reset current score sb.prep_high_score() # Reset maximum score sb.prep_level() # Reset game level sb.prep_ships() # Reset available ships # Clear alien and bullet list aliens.empty() bullets.empty() # Create a new group of aliens and center it 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""" screen.fill(ai_settings.bg_color) # Fills the screen with the specified color for bullet in bullets: bullet.draw_bullet() ship.blitme() # Display the spacecraft on the screen aliens.draw(screen) # Let aliens appear on the screen sb.show_score() # Print scoring information if not stats.game_active: # Print the start button if the game is inactive play_button.draw_button() pygame.display.flip() # Displays the most recently drawn screen def update_bullets(ai_settings, screen, stats, sb, ship, aliens, bullets): """Update the location of bullets and delete bullets that have disappeared""" bullets.update() # The number of lists or groups should not be modified in the for loop, which will lead to the loss of traversal for bullet in bullets.copy(): if bullet.rect.bottom <= 0: bullets.remove(bullet) check_bullet_alien_collisions(ai_settings, screen, stats, sb, ship, aliens, bullets) # print(len(bullets)) # Show how many bullets there are. This knowledge test. Deleting this statement at run time can reduce memory def check_bullet_alien_collisions(ai_settings, screen, stats, sb, ship, aliens, bullets): """Respond to the collision between bullets and aliens, and generate a new group of aliens after all aliens die""" # Detect whether a bullet hit the alien. If so, delete the bullet and alien collisions = pygame.sprite.groupcollide(bullets, aliens, True, True) if collisions: # Increase score when hitting aliens for aliens in collisions.values(): stats.score += ai_settings.alien_point * len(aliens) sb.prep_score() check_high_score(stats, sb) if len(aliens) == 0: # If all aliens are eliminated, delete the existing bullets and regenerate aliens bullets.empty() ai_settings.increase_speed() # Raise the level stats.level += 1 sb.prep_level() create_fleet(ai_settings, screen, ship, aliens) def fire_bullet(ai_settings, screen, ship, bullets): """If the firing limit is not reached, fire a bullet""" if len(bullets) < ai_settings.bullets_allowed: new_bullet = Bullet(ai_settings, screen, ship) # Create an instance of the bullet bullets.add(new_bullet) # Place bullet instances in groups def get_number_rows(ai_settings, ship_height, alien_height): """Calculate how many lines the screen can hold""" # Calculate how much space is left on the screen available_space_y = ai_settings.screen_height - 4 * alien_height - ship_height # How many lines are there on the calculation screen number_rows = int(available_space_y / (2 * alien_height)) return number_rows def get_number_alien_x(ai_settings, alien_width): """Calculate how many aliens each row can hold""" # Calculate how many positions there are in a row available_space_x = ai_settings.screen_width - 2 * alien_width # Calculate how many aliens a row can hold number_alien_x = int(available_space_x / (2 * alien_width)) return number_alien_x def create_alien(ai_settings, screen, aliens, alien_number, row_number): """Create an alien and put it in the current line""" alien = Alien(ai_settings, screen) # Create an alien alien_width = alien.rect.width # Get the width of an alien alien_height = alien.rect.height alien.x = alien_width + 2 * alien_width * alien_number # Set the initial position of each alien alien.rect.x = alien.x # Determine the vertical position of each alien alien.rect.y = alien_height + 2 * alien_height * row_number aliens.add(alien) # Adding aliens to a group def create_fleet(ai_settings, screen, ship, aliens): """Create alien groups""" alien = Alien(ai_settings, screen) # Create an alien number_alien_x = get_number_alien_x(ai_settings, alien.rect.width) number_rows = get_number_rows(ai_settings, ship.rect.height, alien.rect.height) # Create first row for row_number in range(number_rows): for alien_number in range(number_alien_x): create_alien(ai_settings, screen, aliens, alien_number, row_number) def check_fleet_edges(ai_settings, aliens): """When aliens reach the edge, take corresponding measures""" for alien in aliens.sprites(): if alien.check_edge(): change_fleet_direction(ai_settings, aliens) break def change_fleet_direction(ai_settings, aliens): """Move all 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, sb, screen, ship, aliens, bullets): """Responding to a spaceship hit by aliens""" if stats.ships_left > 0: stats.ships_left -= 1 # Reduce the number of ships by one sb.prep_ships() # Update scoreboard # Clear the list of bullets and aliens aliens.empty() bullets.empty() # Create a new group of aliens and put the spacecraft in the center of the screen create_fleet(ai_settings, screen, ship, aliens) # Create new aliens ship.center_ship() # Move the spacecraft to the center of the screen # suspend sleep(0.5) else: stats.game_active = False pygame.mouse.set_visible(True) def check_aliens_bottom(ai_settings, stats, sb, screen, ship, aliens, bullets): """Check if aliens have reached the bottom of the screen""" screen_rect = screen.get_rect() # Read the matrix information of the screen for alien in aliens: # If the coordinates of the alien's bottom matrix are larger than the screen, the collision response is performed if alien.rect.bottom >= screen_rect.bottom: ship_hit(ai_settings, stats, sb, screen, ship, aliens, bullets) break def update_aliens(ai_settings, stats, sb, screen, ship, aliens, bullets): """Update the location of Aliens""" check_fleet_edges(ai_settings, aliens) aliens.update() # Detect the collision between aliens and spacecraft if pygame.sprite.spritecollideany(ship, aliens): ship_hit(ai_settings, stats, sb, screen, ship, aliens, bullets) check_aliens_bottom(ai_settings, stats, sb, screen, ship, aliens, bullets) def check_high_score(stats, sb): """Check whether the highest score is born""" if stats.score > stats.high_score: stats.high_score = stats.score sb.prep_high_score()
alien.py
# Initialize alien related modules, alien py import pygame from pygame.sprite import Sprite class Alien(Sprite): def __init__(self, ai_settings, screen): """Initialize the alien and set its starting position""" super().__init__() self.screen = screen self.ai_settings = ai_settings # Load the alien image and set its rect property self.image = pygame.image.load("images/alien.bmp") self.rect = self.image.get_rect() # Let each alien appear near the upper left corner of the screen self.rect.x = self.rect.width # Left margin set to alien width self.rect.y = self.rect.height # The top margin is set to alien height # Store the exact location of aliens self.x = float(self.rect.x) # It is mainly used for back calculation def blitme(self): """Draw aliens at the specified location""" self.screen.blit(self.image, self.rect) def check_edge(self): """If the alien is on the edge of the screen, return True""" screen_rect = self.screen.get_rect() # If the edge of the alien is greater than or equal to the right edge of the screen if self.rect.right >= screen_rect.right: return True # If the edge of the alien is less than or equal to the left edge of the screen, i.e. coordinate 0 elif self.rect.left <= 0: return True def update(self): """Move aliens to the right""" self.x += (self.ai_settings.alien_speed * self.ai_settings.fleet_direction) self.rect.x = self.x
settings.py
# Store game related setting information, settings py class Settings: """Store all classes related to alien invasion""" def __init__(self): """Initialize game static settings""" # screen setting self.screen_width = 1200 # Set window width self.screen_height = 700 # Set window height self.bg_color = (230, 230, 230) # Set background color # Spacecraft setup self.ship_limit = 3 # Set the maximum number of ships for players # Bullet setting self.bullet_width = 300 # The width of the bullet self.bullet_height = 15 # Bullet height self.bullet_color = (60, 60, 60) # Bullet color self.bullets_allowed = 3 # Limit the number of bullets that do not disappear to 3 # Alien settings self.fleet_drop_speed = 10 # The speed at which aliens move down self.speed_up = 1.1 # What kind of speed to accelerate the pace of the game self.score_scale = 1.5 # Speed up scores self.initialize_dynamic_speed() def initialize_dynamic_speed(self): """The amount of dynamic change as the game progresses""" self.ship_speed = 1.5 # Set the initial value of spacecraft speed self.bullet_speed = 3 # Bullet speed self.alien_speed = 0.5 # Aliens move at a speed of 0.5 self.alien_point = 50 # Points per alien defeated # fleet_ When direction is 1, it means to move right, and when direction is - 1, it means to move left self.fleet_direction = 1 def increase_speed(self): """Speed up""" self.ship_speed *= self.speed_up self.bullet_speed *= self.speed_up self.alien_speed *= self.speed_up self.alien_point = int(self.alien_point * self.score_scale) # print(self.alien_point) # Print and display the score of the current alien
game_stats.py
# Module for storing game statistics, game_stats.py class GameStats: """Track game statistics""" def __init__(self, ai_settings): self.ai_settings = ai_settings self.reset_stats() self.game_active = False # The game has just started and is active self.high_score = 0 # The highest score should not be reset at any time def reset_stats(self): """Initialize information that may change during game operation""" # Count the number of ships remaining in the game self.ships_left = self.ai_settings.ship_limit self.score = 0 # Count game scores self.level = 1 # Count the level information of the game
bullet.py
# Initialize the module of the bullet py import pygame from pygame.sprite import Sprite class Bullet(Sprite): """A class used to manage the firing of bullets from a spacecraft""" def __init__(self, ai_settings, screen, ship): """Add a bullet object to the position of the ship""" super(Bullet, self).__init__() self.screen = screen # Create a rectangle representing the bullet at (0, 0) and set the correct position. self.rect = pygame.Rect(0, 0, ai_settings.bullet_width, ai_settings.bullet_height) self.rect.centerx = ship.rect.centerx # Set the centerx of the bullet to the centerx of the ship self.rect.top = ship.rect.top # Set the top of the bullet to the top of the ship # Store bullet position in decimal self.y = float(self.rect.y) # Store the y coordinate of the bullet in decimal places self.color = ai_settings.bullet_color # Sets the color of the bullet self.speed = ai_settings.bullet_speed # Set the speed of the bullet def update(self): """Move the bullet up""" self.y -= self.speed self.rect.y = self.y def draw_bullet(self): """Draw bullets on the screen""" pygame.draw.rect(self.screen, self.color, self.rect)
button.py
# For information about initializing game buttons, see button py import pygame.ftfont # The module can render text to the screen class Button: # message is the text we want to display in the button def __init__(self, ai_settings, screen, message): """Initialize button properties""" self.screen = screen self.screen_rect = screen.get_rect() # Set the size and other properties of the button self.width, self.height = 200, 50 self.button_color = (0, 255, 0) # The button is set to green self.text_color = (255, 255, 255) # The text content is set to white self.font = pygame.font.SysFont(None, 48) # None indicates the default font and 48 indicates the font size # Create a rect object for the button and center it self.rect = pygame.Rect(0, 0, self.width, self.height) self.rect.center = self.screen_rect.center # Create a label for the button self.prep_msg(message) def prep_msg(self, message): """take message Render as an image and center it in the button""" self.msg_image = self.font.render(message, True, self.text_color, self.button_color) # Convert text to image self.msg_image_rect = self.msg_image.get_rect() self.msg_image_rect.center = self.rect.center def draw_button(self): """Draw a button before you draw text""" self.screen.fill(self.button_color, self.rect) # Draw button self.screen.blit(self.msg_image, self.msg_image_rect) # Draw text
scoreboard.py
# Score statistics and rendering for image printing module, scoreboard py import pygame.ftfont from pygame.sprite import Group from ship import Ship class Scoreboard: """Class that displays score information""" def __init__(self, ai_settings, screen, stats): """Initialize the attributes involved in displaying scores""" self.screen = screen self.screen_rect = screen.get_rect() self.ai_settings = ai_settings self.stats = stats # Font setting for displaying score information self.text_color = (30, 30, 30) self.font = pygame.font.SysFont(None, 48) # Prepare to display the image of the current score and the highest score self.prep_score() self.prep_high_score() self.prep_level() self.prep_ships() def prep_score(self): """Render scores as images""" rounded_score = int(round(self.stats.score, -1)) score_str = "{:,}".format(rounded_score) self.score_image = self.font.render(score_str, True, self.text_color, self.ai_settings.bg_color) # Displays the score in the upper right corner 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 in the 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 = 20 def prep_level(self): """Convert levels to images""" self.level_image = self.font.render(str(self.stats.level), True, self.text_color, self.ai_settings.bg_color) # Put the grade 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_settings, self.screen) ship.rect.x = 10 + ship_number * ship.rect.width ship.rect.y = 10 self.ships.add(ship) def show_score(self): """Show score""" self.screen.blit(self.score_image, self.score_rect) # Displays the current score self.screen.blit(self.high_score_image, self.high_score_rect) # Show highest score self.screen.blit(self.level_image, self.level_rect) # Drawing spacecraft self.ships.draw(self.screen)
epilogue
If you have any questions in learning, please leave a message in the comment area. You will reply when you see it. Let's cheer together.