python application chapter alien invasion project - scoring (middle)

foreword

  The last article mainly introduced the addition of one in "Alien Invasion" play按钮, and reset the game. In addition, when the player was playing, he increased the level of the game, and first modified the speed of the spaceship. This article introduces you to the last part of the project - scoring. First of all, I will introduce the implementation of the display score.
  Next, we implement a scoring system to track the player's score in real time and display the highest score, current level, and remaining ships.
  The score is a statistic for the game, so we GameStatesadd a scoreproperty to it:

    def reset_stats(self):
        """初始化在遊戲運行期間可能變化的統計信息"""
        self.ships_left = self.ai_settings.ship_limit
        self.score = 0

  To reset the score every time we start the game, we initialize the score in rect_stats()instead of .__init__()

1. Display the score

  To display the score on the screen, we first create a new class Scoreboard. For now, this class only shows the current score, but we'll use it later to show the highest score, level, and number of ships remaining. The following is the first half of this class, which is saved as a file scoreboard.py, and the specific file directory is as follows:

  Next, Scoreboard类the first part of our implementation:

import pygame.font
class Scoreboard():
    """显示得分信息的类"""

    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)
        # 准备初始得分图像
        self.prep_score()

  Since Scoreboard类the text is displayed on the screen, we first import the module pygame.font. Next, we __init__()include the formal parameter ai_settings、screen和satasin it so that it can report the value we're tracking. 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):
        """将得分转换为一幅渲染的图像"""
        score_str = str(self.stats.score)
        self.score_image = self.font.render(score_str, True, self.text_color,
                                            self.ai_settings.bg_color)
        # 将得分放在屏幕右上角
        self.score_rect = self.score_image.get_rect()
        self.score_rect.right = self.screen_rect.right - 20
        self.score_rect.top = 20

  In prep_score(), we first convert the numeric value stats.scoreto a string, and then pass this string to the one that created the image render(). To display the score clearly on the screen, we render()pass the screen background color, as well as the text color.
  We put the scores in the upper right corner of the screen and stretch them to the left as the score increases causing the number to be wider. To ensure that the score is always anchored to the right side of the screen, we create a rect called score_rectrect whose right edge is 20 pixels from the right edge of the screen, and whose top edge is also 20 pixels from the top edge of the screen.
  Finally, we create the method show_score()that displays the rendered score image:

def show_score(self):
        """在屏幕上显示得分"""
        self.screen.blit(self.score_image, self.score_rect)

  This method displays the score image on the screen and places it at the score_rectspecified location.

2. Create a scoreboard

  To display the score, we alien_invasion.pycreate an Scoreboardinstance in:

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():
    # 初始化游戏并创建一个屏幕对象
    pygame.init()
    ai_settings = Settings()
    screen = pygame.display.set_mode((ai_settings.screen_width, ai_settings.screen_height))
    pygame.display.set_caption("Alian Invasion")
    # 创建play按钮
    play_button = Button(ai_settings, screen, "Play")
    # 創建一個用于存儲遊戲統計信息的實例
    stats = GameStats(ai_settings)
    sb = Scoreboard(ai_settings, screen, stats)
    # 创建一艘飞船、一个子弹编组和一个外星人编组
    ship = Ship(ai_settings, screen)
    # 创建一组一个用于存储子弹的编组
    bullets = Group()
    aliens = Group()
    # 创建外星人群
    # alien = Alien(ai_settings, screen)
    gf.create_fleet(ai_settings, screen, ship, aliens)
    # 开始游戏的主循环
    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, 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 Scoreboardand after creating the instance we create an instance statscalled sb , next, we pass sb to , which enables it to display the score on the screen.   To display the score, it will be modified as follows:sbScoreboardupdate_screen()
update_screen()

def update_screen(ai_settings, screen, stats, sb, ship, aliens, bullets,
        play_button):
    """更新屏幕上的图像,并切换到新屏幕"""
    # 每次循环时都重绘屏幕
    screen.fill(ai_settings.bg_color)
    # 在飞船和外星人后面重绘所有子弹
    for bullet in bullets.sprites():
        bullet.draw_bullet()
    ship.blitme()
    aliens.draw(screen)
    # 显示得分
    sb.show_score()
    # 如果游戏处于非活动状态,就绘制play添加按钮
    if not stats.game_active:
        play_button.draw_button()
    # 让最近绘制的屏幕可见
    pygame.display.flip()

  We update_screen()added it to the parameter list of sb, and called it before drawing the play button show_score.
  If we were running the game, you would see 0 in the upper right corner of the screen (for now, we just want to make sure the score is in the right place before developing the scoring system any further). The score rendering before the game starts is as follows:

  Let's specify how many points each alien is worth!

3. Update the score when the aliens are destroyed

  To display the score on the screen in real time, every time an alien is hit, we update stats.scorethe value and call the prep_score()update score image. But before again, we need to specify how many points the player will get for every alien shot down:

    def initialize_dymaic_settings(self):
        """初始化随游戏进行而变化的设置"""
        self.ship_speed_factor = 1.5
        self.bullet_speed_factor = 3
        self.alien_speed_factor = 1
        # fleet_direction为1表示向右移动,为-1表示向左移动
        self.fleet_direction = 1
        # 记分
        self.alien_points = 50

  As the game progresses, we will increase the number of points for each alien value. To ensure this value is reset every time a new game is started, we initialize_dynamic_settings()set it in .
  In check_bullet_alien_collisions(), the score is updated every time an alien is shot down:

def check_bullet_alien_collisions(ai_settings, screen, stats, sb,  ship, aliens, 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)

  Our updated check_bullet_alien_collisions()definition, which includes the formal parameter statssum sb, allows it to update the score and scoreboard. When a bullet hits the alien, pygame returns a dictionary (collision). We check to see if this dictionary exists, and if so, add an alien-valued point to the score. Next, we call prep_score()to create a new image showing the latest score.
  We need to modify update_bullets()it to make sure that the proper arguments are passed between functions:

def update_bullets(ai_settings, screen, stats, sb, ship, aliens, bullets):
    """更新子弹的位置,并删除已消失的子弹"""
    # 更新子弹的位置
    bullets.update()
    # 删除已消失的子弹
    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_bullets()the definition of , you need to add formal parameters statsand , and when sbcalling check_bullet_alien_collisions(), you also need to pass the actual parameters .   We also need to modify the code called in the main loop :statssb
whileupdate_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():
    # 初始化游戏并创建一个屏幕对象
    pygame.init()
    ai_settings = Settings()
    screen = pygame.display.set_mode((ai_settings.screen_width, ai_settings.screen_height))
    pygame.display.set_caption("Alian Invasion")
    # 创建play按钮
    play_button = Button(ai_settings, screen, "Play")
    # 創建一個用于存儲遊戲統計信息的實例
    stats = GameStats(ai_settings)
    sb = Scoreboard(ai_settings, screen, stats)
    # 创建一艘飞船、一个子弹编组和一个外星人编组
    ship = Ship(ai_settings, screen)
    # 创建一组一个用于存储子弹的编组
    bullets = Group()
    aliens = Group()
    # 创建外星人群
    # alien = Alien(ai_settings, screen)
    gf.create_fleet(ai_settings, screen, ship, aliens)
    # 开始游戏的主循环
    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)
run_game()

  When calling update_bullets(), you need to pass the actual parameters statsand sb.
  If we run the game now, the score will keep increasing as follows:

4. The points of each alien killed will be counted into the score

  At the time, our code probably had a bug that missed some destroyed aliens. For example, if two bullets hit the alien in a loop, or if the factor bullet is wider and multiple aliens are hit at the same time, the player will only get points for one destroyed alien. To fix this, let's adjust the way we detect collisions between bullets and aliens.
  In check_bullet_alien_collisions(), the bullets that collided with the aliens are all collisionsa key in a dictionary; and the value associated with each bullet is a list containing the aliens that bullet hit. We iterate through the dictionary collsions, making sure to score points for each alien killed:

def check_bullet_alien_collisions(ai_settings, screen, stats, sb,  ship, aliens, 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 collisionsexists, we iterate over all the values ​​in it. Don't forget, each value is a list of all aliens hit by the same bullet. For each list, multiply an alien's points by the number of aliens it contains, and add the result to the current score. To test this, change the bullet width to 300px and verify that we get points per alien hit by the wider bullet, then return the bullet width to normal.

5. Increase the number of points

  The game gets harder each time the player goes up a level, so at higher levels the aliens should have higher points. To achieve this, let's add some code to increase the number of points as the pace of the game increases:

class Settings():
    """存储《外星人入侵》的所有设置类"""
    def __init__(self):
        """初始化游戏的设置"""
        # 屏幕的设置
        self.screen_width = 1400
        self.screen_height = 700
        self.bg_color = (230, 230, 230)
        # 飞船的设置
        self.ship_limit = 3
        # 子弹设置
        self.bullet_width = 3
        self.bullet_height = 15
        self.bullet_color = 60, 60, 60
        self.bullets_allowed = 6
        # 外星人设置
        self.fleet_drop_speed = 10
        # 以什么样的速度加速游戏节奏
        self.speedup_scale = 1.1
        # 外星人点数的提高速度
        self.score_scale = 1.5
        self.initialize_dymaic_settings()
    def initialize_dymaic_settings(self):
        """初始化随游戏进行而变化的设置"""
        self.ship_speed_factor = 1.5
        self.bullet_speed_factor = 3
        self.alien_speed_factor = 1
        # fleet_direction为1表示向右移动,为-1表示向左移动
        self.fleet_direction = 1
        # 记分
        self.alien_points = 50
    def increase_speed(self):
        """提高速度设置"""
        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 rate at which points increase and call it score_scale. The small rhythm acceleration makes the game very challenging very quickly, but in order for the score to change significantly, the point increase rate needs to be set to a larger value. Now, we've increased the number of points per alien while speeding up the game. To make the number of points an integer, we use a function int().
  To display the alien's points, we have added a print statement to settingsthe method of . increase_speed()So now every time we increase a level, we will see the new point value in the terminal window. What we need to pay attention to here is:We use the print statement for testing here. 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 the player.

6. Round the score

  Most arcade-style shooters display scores in multiples of 10, so let's follow that with our scoring system. We'll also format the score, adding commas to represent thousands separators in large numbers. We Scoreboardperform this modification in:

    def prep_score(self):
        """将得分转换为一幅渲染的图像"""
        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)
        # 将得分放在屏幕右上角
        self.score_rect = self.score_image.get_rect()
        self.score_rect.right = self.screen_rect.right - 20
        self.score_rect.top = 20

  Functions round()usually make decimals accurate to the number of decimal places, where the number of decimal places is specified by the second argument. However, if the second argument is specified as a negative number, round()the circle is rounded to the nearest integer multiple of 10, 100, 1000, etc. At the same time, we also use a string formatting directive that tells Python to insert commas when converting numbers to strings, for example, to output 1,000,000 instead of 1,000,000. If we played the game at this point, what we would see would be Scores in integer multiples of 10, even if the score is high, separated by commas, as follows:

Summarize

  The last article mainly introduced the addition of one in "Alien Invasion" play按钮, and reset the game. In addition, when the player was playing, he increased the level of the game, and first modified the speed of the spaceship. This article introduces you to the last part of the project - scoring. This article introduces to you the realization of related functions such as displaying the score, creating a scoreboard, updating the score when the aliens are destroyed, increasing the number of points and taking the score in the scoring module. However, this article only writes part of the code in part of the code, 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 the article reading time should be controlled as much as possible within 20 minutes or so. However, the accuracy of the code must be correct and it can run! Therefore, I hope that everyone can read it carefully, write the code carefully, and understand the in-depth meaning, so that the value of this project can be maximized. In fact, this project is already very typical, the code is everywhere, but if you simply paste and copy, it will not have any value for your knowledge learning, you still have to follow it again, and then you need to know the meaning of each line of code or use When it comes to the knowledge point we introduced earlier, only in this way will this project play a different value. I hope everyone will study hard and solidify the basic knowledge. Python is a practical language, it is the simplest of many programming languages, and it is also the best to get started. When you have learned the language, it is relatively simple to learn java, go and C. Of course, Python is also a popular language, which is very helpful for the realization 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 that we will learn something. come on! ! !In addition, I am very happy. In the 2021s11 League of Legends global finals, congratulations to EDG for winning the game, beating DK 3:2 and winning the championship. Happy! ! ! We are the champions, hahahaha! ! ! !
we are the champion
The LPL era is back

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324134910&siteId=291194637