Python Application Chapter Alien Invasion Project - Alien (End)

foreword

  The last article introduced you to make the alien move, including moving left and right, and moving it down when it encounters the edge of the screen. This article will introduce the realization of the function of shooting aliens with our spaceship.

shoot aliens

  We created the spaceship and alien crowd, but when the bullet hits the alien, it will go through the alien because we haven't checked for collisions. In game programming, collision refers to the overlapping of game elements. Let the bullets shoot down the aliens. We will use to sprite.groupcollide()detect collisions between members of two groups.

1. Detect the collision of bullets and aliens

  We need to know right away when a bullet hits an alien, so that the alien disappears immediately after the collision. To do this, we'll monitor for collisions immediately after updating the bullet's position.
  The method sprite.groupcollider()compares each bullet to recteach alien rectand returns a dictionary of bullets and aliens that collided. In this dictionary, each key is a bullet, and the corresponding value is the alien that was hit.Spoiler ahead, we'll use this dictionary later.
  In the function update_bullets(), use the following code to check for collisions:

import sys
import pygame
from bullet import Bullet
from alien import Alien
def check_keydown_events(event, ai_settings, screen, ship, bullets):
    """响应按键"""
    if event.key == pygame.K_RIGHT:
        ship.moving_right = True
    elif event.key == pygame.K_LEFT:
        ship.moving_left = True
    elif event.key == pygame.K_SPACE:
        # 创建一颗子弹,并将其加入到编组bullets中
        fire_bullet(ai_settings, screen, ship, bullets)
    elif event.key == pygame.K_q:
        sys.exit()
def fire_bullet(ai_settings, screen, ship, bullets):
    """如果还没有到达限制,就发射一颗子弹"""
    if len(bullets) < ai_settings.bullets_allowed:
        new_bullet = Bullet(ai_settings, screen, ship)
        bullets.add(new_bullet)
def check_keyup_events(event, ship):
    """响应松开"""
    if event.key == pygame.K_RIGHT:
        ship.moving_right = False
    elif event.key == pygame.K_LEFT:
        ship.moving_left = False
def check_events(ai_settings, screen, ship, bullets):
    """响应按键和鼠标事件"""
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()
        elif event.type == pygame.KEYDOWN:
            check_keydown_events(event, ai_settings, screen, ship, bullets)
        elif event.type == pygame.KEYUP:
            check_keyup_events(event, ship)

def update_screen(ai_settings, screen, ship, aliens, bullets):
    """更新屏幕上的图像,并切换到新屏幕"""
    # 每次循环时都重绘屏幕
    screen.fill(ai_settings.bg_color)
    # 在飞船和外星人后面重绘所有子弹
    for bullet in bullets.sprites():
        bullet.draw_bullet()
    ship.blitme()
    aliens.draw(screen)
    # 让最近绘制的屏幕可见
    pygame.display.flip()
def update_bullets(aliens, bullets):
    """更新子弹的位置,并删除已消失的子弹"""
    # 更新子弹的位置
    bullets.update()
    # 删除已消失的子弹
    for bullet in bullets.copy():
        if bullet.rect.bottom <= 0:
            bullets.remove(bullet)
    """更新子弹的位置,并删除已消失的子弹"""
    collisions = pygame.sprite.groupcollide(bullets, aliens, True, True)
def get_number_aliens_x(ai_settings, alien_width):
    avaliable_space_x = ai_settings.screen_width - 2 * alien_width
    number_aliens_x = int(avaliable_space_x / (2 * alien_width))
    return number_aliens_x
def create_alien(ai_settings, screen, aliens, alien_number, row_number):
    # 创建一个外星人,并计算一行可容纳多少个外星人
    alien = Alien(ai_settings, screen)
    alien_width = alien.rect.width
    alien.x = alien_width + 2 * alien_width * alien_number
    alien.rect.x = alien.x
    alien.rect.y = alien.rect.height + 2 * alien.rect.height * row_number
    aliens.add(alien)
def create_fleet(ai_settings, screen, ship,  aliens):
    """创建外星人群"""
    alien = Alien(ai_settings, screen)
    number_aliens_x = get_number_aliens_x(ai_settings, alien.rect.width)
    number_rows = get_number_rows(ai_settings, ship.rect.height, alien.rect.height)
    # 创建第一行外星人
    for row_number in range(number_rows):
        for alien_number in range(number_aliens_x):
            # 创建一个外星人并将其加入当前行
            create_alien(ai_settings, screen, aliens, alien_number, row_number)
def get_number_rows(ai_settings, ship_height, alien_height):
    """计算屏幕可容纳多少行外星人"""
    available_space_y = (ai_settings.screen_height - (3 * alien_height) - ship_height)
    number_rows = int(available_space_y / (2 * alien_height))
    return number_rows
def check_fleet_edges(ai_settings, aliens):
    """有外星人到达边缘时采取相应措施"""
    for alien in aliens.sprites():
        if alien.check_edges():
            change_fleet_direction(ai_settings, aliens)
            break
def change_fleet_direction(ai_settings, aliens):
    """将整群外星人向下移,并改变他们的方向"""
    for alien in aliens.sprites():
        alien.rect.y += ai_settings.fleet_drop_speed
    ai_settings.fleet_direction = -1
def update_aliens(ai_settings, aliens):
    """检查是否有外星人位于屏幕边缘,并更新整群外星人的位置"""
    check_fleet_edges(ai_settings, aliens)
    aliens.update()

  This new line of code iterates over bulletseach bullet in the group, and then iterates over alienseach alien in the group. rectWhenever there is an overlap of bullets and aliens groupcollide(), add a key-value pair to the returned dictionary. The two arguments Truetell Pygame to remove the bullet and alien that collided. (To simulate a high-energy bullet that travels to the top of the screen - destroying every alien it hits, set the first boolean argument to False and the second to True. This gets hit will disappear, but all bullets remain active until they reach the top of the screen).
  When we call update_bullets(), we pass arguments aliens:

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

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")
    # 创建一艘飞船、一个子弹编组和一个外星人编组
    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, ship, bullets)
        ship.update()
        gf.update_bullets(aliens, bullets)
        gf.update_aliens(ai_settings, aliens)
        gf.update_screen(ai_settings, screen, ship, aliens, bullets)
run_game()

  If we run the game at this time, the aliens that are hit will disappear, and we will see the aliens being shot down. The specific renderings are as follows:

2. Create Big Bullets for Testing

  You can test many of its features just by running the game, but some are cumbersome to test under normal circumstances. For example, to test whether the code correctly handles the situation where the alien group is empty, it takes a long time to shoot down the aliens on the screen.
  when testing these functions. Certain settings of the game can be modified in order to focus on specific aspects of the game. For example, the screen can be reduced to reduce the number of aliens that need to be shot down, or the speed of bullets can be increased. In order to be able to fire a large number of bullets per unit time.
  When testing this game, one modification I usually make is to increase the size of the bullet so that it will still be effective after hitting the alien. However, it should be noted that after we test, the value that must be changed must be changed back! ! ! !

3. Generate a new alien population

  An important feature of this game is that there are endless aliens. After an alien population is eliminated, a group of aliens is displayed. First, you need to check alienswhether the group is empty. Called if empty create_fleet(). We're going update_bullets()to perform this check in , because aliens are all wiped out here. The specific implementation is as follows:

def update_bullets(ai_settings, screen, ship, aliens, bullets):
    """更新子弹的位置,并删除已消失的子弹"""
    # 更新子弹的位置
    bullets.update()
    # 删除已消失的子弹
    for bullet in bullets.copy():
        if bullet.rect.bottom <= 0:
            bullets.remove(bullet)
    """更新子弹的位置,并删除已消失的子弹"""
    collisions = pygame.sprite.groupcollide(bullets, aliens, True, True)
    if len(aliens) == 0:
        bullets.empty()
        create_fleet(ai_settings, screen, ship, aliens)

  We check if the marshalling aliensis empty. If so, use the method to empty()delete all remaining bullets in the group, . We also called create_fleet(), again showing a bunch of aliens on the screen.
  Now, update_bullets()the definition of contains extra parameters ai_settings、screen和ship, so we need to update alien_invasion.pythe update_bullets()call to:

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

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")
    # 创建一艘飞船、一个子弹编组和一个外星人编组
    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, ship, bullets)
        ship.update()
        gf.update_bullets(ai_settings, screen, ship, aliens, bullets)
        gf.update_aliens(ai_settings, aliens)
        gf.update_screen(ai_settings, screen, ship, aliens, bullets)
run_game()

  Now, after the current alien population is wiped out, a new alien population will appear immediately.

4. Increase bullet speed

  If you try to shoot aliens in this game now, you might find that the bullets are slower than before, because pygame has to do more work on each loop. To increase the speed of the bullet, settings.pythe bullet_speed_factorvalue in can be adjusted. For example, if this value is increased to 3, the bullet will travel up the screen considerably faster:

class Settings():
    """存储《外星人入侵》的所有设置类"""
    def __init__(self):
        """初始化游戏的设置"""
        # 屏幕的设置
        self.screen_width = 1400
        self.screen_height = 700
        self.bg_color = (230, 230, 230)
        # 飞船的设置
        self.ship_speed_factor = 1.5
        # 子弹设置
        self.bullet_speed_factor = 3
        self.bullet_width = 3
        self.bullet_height = 15
        self.bullet_color = 60, 60, 60
        self.bullets_allowed = 6
        # 外星人设置
        self.alien_speed_factor = 1
        self.fleet_drop_speed = 10
        # fleet_direction为1表示向右移动,为-1表示向左移动
        self.fleet_direction = 1

  Of course, the speed of your own system is different, and the speed of the bullet also has an impact. Therefore, you can then configure the corresponding bullet speed according to your computer.

5. Refactor update_bullets()

  Let's refactor update_bullets()so that it doesn't do so many tasks anymore. We'll move the code that handles the bullet and alien collision into a separate function:

def update_bullets(ai_settings, screen, 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, ship, aliens, bullets)
def check_bullet_alien_collisions(ai_settings, screen, ship, aliens, bullets):
    """更新子弹的位置,并删除已消失的子弹"""
    collisions = pygame.sprite.groupcollide(bullets, aliens, True, True)
    if len(aliens) == 0:
        bullets.empty()
        create_fleet(ai_settings, screen, ship, aliens)

  We've created a new function - check_bullet_alien_collisions(), to detect collisions between bullets and aliens, and take action when the entire swarm of aliens is wiped out. This avoids being update_bullets()too long and simplifies subsequent development work.

Summarize

  The last article introduced you to make the alien move, including moving left and right, and moving it down when it encounters the edge of the screen. This article introduces the realization of the function of our spacecraft to shoot aliens, including monitoring the collision of bullets and aliens, generating new alien crowds, increasing the speed of bullets, and refactoring.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! In order to let everyone better absorb the knowledge points used in the project, each of our articles only realizes one function of "Alien Invasion" for everyone, so I hope everyone can read it carefully, write the code carefully, and understand the in-depth Meaning, let's maximize the value of this project. 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! ! !

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=324117720&siteId=291194637