Alien invasion project in python application -- scoring (middle)

Posted by AbydosGater on Sun, 07 Nov 2021 04:06:50 +0100

preface

  Last article It mainly introduces the in alien invasion, adds a play button and resets the game. In addition, when players play, they improve the level of the game and first modify the speed of the spacecraft. This paper introduces the last part of the project - scoring. First of all, let's introduce the implementation of display score.
  next, we implement a scoring system to track players' scores in real time and display the highest score, current level and the number of remaining ships.
   score is a statistical information of the game, so we add a score attribute in GameStates:

    def reset_stats(self):
        """Initializes statistics that may change during game operation"""
        self.ships_left = self.ai_settings.ship_limit
        self.score = 0

  in order to reset the score every time we start the game, we are in rect_stats() instead of__ init__ Initialize score in ().

1. Show score

  to display scores on the screen, we first create a new class Scoreboard. At present, this class only displays the current score, but we will also use it later to display the highest score, level and the number of remaining ships. The following is the first half of this class, which is saved as the file scoreboard.py. The specific file directory is as follows:

  next, we implement the first part of the Scoreboard class:

import pygame.font
class Scoreboard():
    """Class that displays score information"""

    def __init__(self, ai_settings, screen, stats):
        """Initialize scorekeeping attributes."""
        self.screen = screen
        self.screen_rect = screen.get_rect()
        self.ai_settings = ai_settings
        self.stats = stats

        # Font settings for scoring information.
        self.text_color = (30, 30, 30)
        self.font = pygame.font.SysFont(None, 48)
        # Prepare initial score image
        self.prep_score()

  since the Scoreboard class displays text on the screen, we first import the module pygame.font. Next, we are__ init__ () contains formal parameter ai_settings, screen, and satas, so that it can report the values we track. Then, we set the text color and instantiate a font object.
  to convert the text to be displayed into an image, we call prep_score(), which is defined as follows:

    def prep_score(self):
        """Convert the score to a rendered image"""
        score_str = str(self.stats.score)
        self.score_image = self.font.render(score_str, True, self.text_color,
                                            self.ai_settings.bg_color)
        # 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

  in prep_ In score (), we first convert the digital value stats.score into a string, and then pass this string to render() which creates the image. In order to clearly display the score on the screen, we passed the screen background color and text color to render().
  we put the scores in the upper right corner of the screen and extend them to the left when the score increases to make the number wider. To ensure that the score is always anchored on the right side of the screen, we created a named score_rect of rect, so that its right edge is 20 pixels away from the right edge of the screen, and its upper edge is also 20 pixels away from the upper edge of the screen.
  finally, we create the method show_score() is used to display the rendered score image:

def show_score(self):
        """Show score on screen"""
        self.screen.blit(self.score_image, self.score_rect)

  this method displays the score image on the screen and places it on the score_rect the specified location.

2. Create scoreboard

  to show the score, we are in alien_ Create a Scoreboard instance in invasion.py:

import sys
import pygame
from settings import Settings
from ship import Ship
import game_functions as gf
from pygame.sprite import Group
from alien import Alien
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()
    ai_settings = Settings()
    screen = pygame.display.set_mode((ai_settings.screen_width, ai_settings.screen_height))
    pygame.display.set_caption("Alian Invasion")
    # Create play button
    play_button = Button(ai_settings, screen, "Play")
    # Create an instance to store game statistics
    stats = GameStats(ai_settings)
    sb = Scoreboard(ai_settings, screen, stats)
    # Create a spaceship, a bullet group, and an alien group
    ship = Ship(ai_settings, screen)
    # Create a group for storing bullets
    bullets = Group()
    aliens = Group()
    # Create alien groups
    # alien = Alien(ai_settings, screen)
    gf.create_fleet(ai_settings, screen, ship, aliens)
    # Start the main cycle of the game
    while True:
        # Monitor keyboard and mouse events
        gf.check_events(ai_settings, screen, stats, play_button, ship,
                        aliens, bullets)
        if stats.game_active:
            ship.update()
            gf.update_bullets (ai_settings, screen, 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)
run_game()

  we import the newly created class Scoreboard and create a Scoreboard instance named sb after creating the instance stats. Next, we pass sb to update_screen() enables it to display scores on the screen.
  to display the score, update_ The screen () is modified as follows:

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)
    # Redraw all bullets behind ships and aliens
    for bullet in bullets.sprites():
        bullet.draw_bullet()
    ship.blitme()
    aliens.draw(screen)
    # Show score
    sb.show_score()
    # If the game is inactive, draw the play add button
    if not stats.game_active:
        play_button.draw_button()
    # Make recently drawn screens visible
    pygame.display.flip()

  we're updating_ sb is added to the parameter list of screen (), and show_ is called before drawing the play button. score.
  if we are running this game, you will see 0 in the upper right corner of the screen (at present, we just want to make sure that the score appears in the right place before further developing the scoring system). The score effect before the game is as follows:

  let's specify the value of each alien!

3. Update scores when aliens are destroyed

    in order to display the score on the screen in real time, whenever an alien is hit, we update the value of stats.score and call prep_score() updates the score image. But before again, we need to specify how many points players will get for each alien shot down:

    def initialize_dymaic_settings(self):
        """Initialize settings that change as the game progresses"""
        self.ship_speed_factor = 1.5
        self.bullet_speed_factor = 3
        self.alien_speed_factor = 1
        # fleet_ A direction of 1 means moving to the right, and a direction of - 1 means moving to the left
        self.fleet_direction = 1
        # Scoring
        self.alien_points = 50

  as the game progresses, we will increase the points of each alien value. To ensure that this value is reset every time we start a new game, we use initialize_ dynamic_ Set it in settings().
  check_ bullet_ alien_ In collections(), the score is updated whenever the alien is shot down:

def check_bullet_alien_collisions(ai_settings, screen, stats, sb,  ship, aliens, bullets):
    """Update the location of bullets and delete disappeared bullets"""
    collisions = pygame.sprite.groupcollide(bullets, aliens, True, True)
    if collisions:
        stats.score += ai_settings.alien_points
        sb.prep_score()
    if len(aliens) == 0:
        bullets.empty()
        ai_settings.increase_speed()
        create_fleet(ai_settings, screen, ship, aliens)

  we update check_ bullet_ alien_ The definition of collections () contains the formal parameters stats and sb, so that it can update the score and scoreboard. When a bullet hits an alien, pygame returns a dictionary. We check whether the dictionary exists. If it exists, we add a point of alien value to the score. Next, we call prep_score() to create a new image showing the latest score.
  we need to modify update_bullets(), ensuring that appropriate arguments are passed between functions:

def update_bullets(ai_settings, screen, stats, sb, ship, aliens, bullets):
    """Update the location of bullets and delete disappeared bullets"""
    # Update bullet location
    bullets.update()
    # Delete lost bullets
    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)

  in update_ In the definition of bullets (), you need to add the formal parameters stats and sb, and call check_ bullet_ alien_ You also need to pass the arguments stats and sb when you collect ().
We also need to modify the call to update_ in the main while loop. Code of bullets():

import sys
import pygame
from settings import Settings
from ship import Ship
import game_functions as gf
from pygame.sprite import Group
from alien import Alien
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()
    ai_settings = Settings()
    screen = pygame.display.set_mode((ai_settings.screen_width, ai_settings.screen_height))
    pygame.display.set_caption("Alian Invasion")
    # Create play button
    play_button = Button(ai_settings, screen, "Play")
    # Create an instance to store game statistics
    stats = GameStats(ai_settings)
    sb = Scoreboard(ai_settings, screen, stats)
    # Create a spaceship, a bullet group, and an alien group
    ship = Ship(ai_settings, screen)
    # Create a group for storing bullets
    bullets = Group()
    aliens = Group()
    # Create alien groups
    # alien = Alien(ai_settings, screen)
    gf.create_fleet(ai_settings, screen, ship, aliens)
    # Start the main cycle of the game
    while True:
        # Monitor keyboard and mouse events
        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)
run_game()

  call Update_ When bullets (), you need to pass the arguments stats and sb.
  if we run this game now, the score will continue to increase. The specific effects are as follows:

4. Count the points of each alien eliminated into the score

  at that time, there might be a bug in our code, that is, we missed some eliminated aliens. For example, if two bullets hit aliens in a cycle, or multiple aliens are hit at the same time because the bullets are wider, the player will only get the points of one destroyed alien. To fix this problem, let's adjust the way to detect bullets and alien collisions.
  check_ bullet_ alien_ In collections (), the bullet colliding with aliens is a key in the dictionary collections; The value associated with each bullet is a list of aliens that the bullet hit. We traverse the dictionary collsions to ensure that the points of each alien destroyed are recorded in the score:

def check_bullet_alien_collisions(ai_settings, screen, stats, sb,  ship, aliens, bullets):
    """Update the location of bullets and delete disappeared bullets"""
    collisions = pygame.sprite.groupcollide(bullets, aliens, True, True)
    if collisions:
        for aliens in collisions.values():
            stats.score += ai_settings.alien_points
            sb.prep_score()
    if len(aliens) == 0:
        bullets.empty()
        ai_settings.increase_speed()
        create_fleet(ai_settings, screen, ship, aliens)

   if the dictionary collections exists, we will traverse all the values in it. Don't forget that each value is a list of all aliens hit by the same bullet. For each list, the points of an alien are multiplied by the number of aliens contained in it, and the results are added to the current score. To test this, please change the bullet width to 300 pixels, verify that we get the points of each alien hit by a wider bullet, and then return the bullet width to the normal value.

5. Increase points

  the game becomes more difficult every time the player increases one level, so the points of aliens should be higher at a higher level. To achieve this, we add some code to increase points when the game tempo is accelerated:

class Settings():
    """Store all settings classes of alien invasion"""
    def __init__(self):
        """Initialize game settings"""
        # Screen settings
        self.screen_width = 1400
        self.screen_height = 700
        self.bg_color = (230, 230, 230)
        # Spacecraft settings
        self.ship_limit = 3
        # Bullet settings
        self.bullet_width = 3
        self.bullet_height = 15
        self.bullet_color = 60, 60, 60
        self.bullets_allowed = 6
        # Alien settings
        self.fleet_drop_speed = 10
        # 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_dymaic_settings()
    def initialize_dymaic_settings(self):
        """Initialize settings that change as the game progresses"""
        self.ship_speed_factor = 1.5
        self.bullet_speed_factor = 3
        self.alien_speed_factor = 1
        # fleet_ A direction of 1 means moving to the right, and a direction of - 1 means moving to the left
        self.fleet_direction = 1
        # Scoring
        self.alien_points = 50
    def increase_speed(self):
        """Increase speed setting"""
        self.ship_speed_factor *= self.speedup_scale
        self.bullet_speed_factor *= self.speedup_scale
        self.alien_speed_factor *= self.speedup_scale
        self.alien_points = int(self.alien_points * self.score_scale)
        # print(self.alien_points)

  we define the speed at which points increase and call it score_scale. A small tempo speed up makes the game very challenging quickly, but in order to make a significant change in scoring, you need to set the point increase speed to a larger value. Now, while speeding up the pace of the game, we have increased the points of each alien. To make the number of points an integer, we use the function int().
  in order to display the points of aliens, we increase in the method of settings_ A print statement has been added to speed (). Therefore, now whenever we increase a level, we will see a new point value in the terminal window. What we need to pay attention to here is that we use print statement to test. When we are sure that our logic is correct, we should comment out this statement. Otherwise, it will affect the performance of the game and distract players.

6. Round the score

  most arcade style shooting will display the score as an integral multiple of 10. Let's follow this principle in our scoring system. We will also format the score and add a thousand separator represented by commas to large numbers. We perform this modification in Scoreboard:

    def prep_score(self):
        """Convert the score to a rendered image"""
        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)
        # 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

The     function round() usually makes the decimal accurate to the number of decimal places after the decimal point, where the number of decimal places is specified by the second argument. However, if the second argument is specified as a negative number, round() rounds the circle to the nearest integer multiple of 10, 100, 1000, etc. At the same time, we also use a string format setting instruction, which allows Python to insert commas when converting values into strings, for example, output 1000000 instead of 1000000. If we play this game at this time, we will see an integer multiple score of 10, even if the score is very high, and separate them with commas. The specific effects are as follows:

summary

  Last article It mainly introduces the in alien invasion, adds a play button and resets the game. In addition, when players play, they improve the level of the game and first modify the speed of the spacecraft. This paper introduces the last part of the project - scoring. This paper introduces the implementation of related functions in the scoring module, such as displaying scores, creating scoreboards, updating scores when aliens are eliminated, improving points and taking scores. However, only part of the code is written in this paper, because with the continuous expansion of the project, there are too many lines of code. In order to reduce the length of each article as much as possible, it is convenient for everyone to read and control the reading time of the article to about 20 minutes as much as possible. However, the accuracy of the code must be correct and can run! Therefore, I hope you can read it carefully, write the code carefully, and understand the in-depth meaning, so as to maximize the value of this project. In fact, this project is already very typical, and the code is everywhere. However, if you simply paste and copy, it will not be of any value to your knowledge learning. You still have to follow it, and then you should know the meaning of each line of code or which knowledge point we introduced earlier. Only in this way can this project play a different value, I hope you will study hard and lay a solid foundation of basic knowledge. Python is a language that pays attention to practical operation. It is the simplest and the best entry among many programming languages. When you learn the language, it's easier to learn java, go and C. Of course, Python is also a popular language, which is very helpful for the implementation of artificial intelligence. Therefore, it is worth your time to learn. Life is endless and struggle is endless. We work hard every day, study hard, and constantly improve our ability. I believe we will learn something. come on. In addition, I'm very happy. 2021s11 hero League global finals. Congratulations to EDG for winning the game, beating DK 3-2 and winning the championship. Happy!!! We are champions, hahaha!!!!

Topics: Python pygame