Alien invasion project in python application -- armed spacecraft (end)

Posted by maniac1aw on Wed, 15 Dec 2021 08:00:20 +0100

preface

  Last article , we introduced the left-right movement of the spacecraft, the configuration of the corresponding spacecraft speed and the corresponding restrictions on the motion range of the spacecraft. Finally, check the method_ The events method is reconstructed; And a brief summary of several recent documents is made. This paper introduces the last part of the armed spacecraft - the bullet shooting part of the spacecraft.

Shooting

  next, we add shooting function. We will write the code for players to fire bullets when they press the spacebar. The bullet will empty up the screen and disappear when it reaches the upper edge of the screen.

1. Add bullet settings

  first, update settings Py, in its method__ init__ () store the value required by the new class Bullet at the end:

class Settings():
    """Store all settings classes of alien invasion"""
    def __init__(self):
        """Initialize game settings"""
        # Screen settings
        self.screen_width = 900
        self.screen_height = 600
        self.bg_color = (230, 230, 230)
        # Spacecraft settings
        self.ship_speed_factor = 1.5
        # Bullet settings
        self.bullet_speed_factor = 1
        self.bullet_width = 3
        self.bullet_height = 15
        self.bullet_color = 60, 60, 60

  these settings create a 3-pixel, 15 pixel high dark gray bullet. The speed of the bullet is slightly lower than that of the ship.

2. Create Bullet class

    create the file Bullet to store the Bullet class Py, as follows:

import pygame
from pygame.sprite import Sprite
class Bullet(Sprite):
    """A class that manages bullets fired by spacecraft"""
    def __init__(self, ai_settings, screen, ship):
        """Create a bullet object where the ship is located"""
        super().__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
        self.rect.top = ship.rect.top
        # Stores the bullet position in decimal places
        self.y = float(self.rect.y)

        self.color = ai_settings.bullet_color
        self.speed_factor = ai_settings.bullet_speed_factor
    def update(self):
        """Move the bullet up"""
        # Update the decimal value representing the bullet position
        self.y -= self.speed_factor
        # Update the rect position representing the bullet
        self.rect.y = self.y
    def draw_bullet(self):
        """Draw bullets on the screen"""
        pygame.draw.rect(self.screen, self.color, self.rect)

  the Bullet class inherits from the module pyGame Sprite class imported from sprite. By using sprites, you can group the relevant elements in the game, and then operate all the elements in the group at the same time. To create a Bullet instance, you need to__ init__ () transfer ai_settings, screen and ship instances, and also call super() to inherit sprite.
  first, we created the bullet attribute rect. Bullets are not image-based, so we must use pyGame The Rect () class creates a rectangle starting with a blank space. When creating an instance of this class, you must provide the x and y coordinates of the upper left corner of the rectangle, as well as the width and height of the rectangle. We created this rectangle at (0,0), but the next two lines of code moved it to the correct position, because the initial position of the bullet depends on the current position of the ship. The width and height of the bullet are from AI_ Extracted from settings.
  in addition, we set the centerx of the bullet to the rect of the spacecraft centerx. The bullet should be shot from the top of the ship. Therefore, we set the top attribute of rect representing the bullet to the top attribute of rect of the ship to make the bullet look like it was shot from the ship.
  we store the bullet's y coordinate as a small value so that we can fine tune the bullet's speed. We store the bullet's color and speed settings in self Color and self speed_ In factor.
   the method update() manages the bullet position. After firing, the bullet moves upward in the screen, which means that the Y coordinate will continue to decrease. Therefore, in order to update the bullet position, we start from self Subtract self from y speed_ The value of the factor. Next, we will self rect. Y is set to self The value of Y. Property speed_factor allows us to adjust the behavior of the game by increasing the speed of bullets as the game progresses or as needed. After the bullet is fired, its x coordinate remains unchanged, so the bullet will travel vertically upward along a straight line.
  when we need to draw bullets, we call draw_bullet(). Function draw Rect () is stored in self The color fill in color indicates that the rect of the bullet occupies part of the screen.

3. Store bullets in groups

    after defining the Bullet class and the necessary settings, you can write code. Every time the player presses the spacebar, a Bullet will be fired. First, we will be in alien_invasion.py creates a group to store all valid bullets so that you can manage all bullets fired. This group will be pyGame sprite. An instance of group class; pygame.sprite.Group is similar to a list, but provides additional features to help develop games. In the main loop, we will use this group to draw bullets on the screen and update the position of each Bullet:

import sys
import pygame
from settings import Settings
from ship import Ship
import game_functions as gf
from pygame.sprite import Group

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 a spaceship
    ship = Ship(ai_settings, screen)
    # Create a group for storing bullets
    bullets = Group()
    # Start the main cycle of the game
    while True:
        # Monitor keyboard and mouse events
        gf.check_events(ai_settings, screen, ship, bullets)
        ship.update()
        # Redraw the screen each time you cycle
        bullets.update()
        gf.update_screen(ai_settings, screen, ship, bullets)
run_game()

  we imported pyGame Group class in sprite. First, we created a group instance and named it bullets. This group is created outside the while loop, so you don't need to create a new bullet group every time you run the loop.

  what we need to pay attention to here is that if such a group is created inside the loop, thousands of bullet groups will be created when the game runs, resulting in the game being as slow as a snail. If the game stalls, take a closer look at what happens in the main while loop.

  we passed bullets to check_events() and update_screen(). In check_ In events (), you need to handle bullets when the player presses the spacebar; And in update_ In screen (), we need to update the bullets on the drawing strip screen.
    when we call Update () on the group, the group will automatically call Update () on each wizard. Therefore, the code line bullets Update() assembles the group into bullets and calls bullet update().

4. Fire

  in game_funcation.py, we also need to modify check_keydown_events() to fire a bullet when the player presses the spacebar. We don't need to modify the check_keyup_events(), because nothing happens when the player releases the spacebar. We also need to modify update_screen() ensures that each bullet is redrawn on the screen before calling flip(). Here's the game_function.py related code modifications:

import sys
import pygame
from bullet import Bullet
def check_keydown_events(event, ai_settings, screen, ship, bullets):
    """Response key"""
    if event.key == pygame.K_RIGHT:
        ship.moving_right = True
    elif event.key == pygame.K_LEFT:
        ship.moving_left = True
    elif event.key == pygame.K_SPACE:
        # Create a bullet and add it to the group bullets
        new_bullet = Bullet(ai_settings, screen, ship)
        bullets.add(new_bullet)
def check_keyup_events(event, ship):
    """Response release"""
    if event.key == pygame.K_RIGHT:
        ship.moving_right = False
    elif event.key == pygame.K_LEFT:
        ship.moving_left = False
def check_events(ai_settings, screen, ship, bullets):
    """Respond to key and mouse events"""
    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, bullets):
    """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()
    # Make recently drawn screens visible
    pygame.display.flip()

  grouping bullets passed to check_keydown_events(). When the player presses the spacebar, a new Bullet (a Bullet instance named new_bullet) is created and added to the group bullets using the method add(). Code bullets Add (new Bullet) stores the new Bullet in the group bullets.
  check_ In the definition of eventd (), we need to add the formal parameter bullets; Call check_keydown_events(), we also need to pass bullets as arguments to it.
  in addition, we give update to draw bullets on the screen_ Screen () adds the formal parameter bullets. Method bullets Sprites () returns a list of all sprites in the group bullets. To draw all the bullets fired on the screen, we traverse the sprites in the grouped bullets and call draw for each sprite_ bullet().
  if alien is running at this time_ invasion. Py, will be able to move the spacecraft left and right and fire any number of bullets. The bullet went up the screen and disappeared at the top of the screen. Of course, we were in settings Py to modify the size, color and speed of bullets.

5. Delete lost bullets

  the bullets will disappear when they reach the top of the screen, just because pygame can't draw them outside the screen. These bullets are actually still there. Their y coordinate is negative and getting smaller and smaller. This is a problem because they will continue to consume memory and processing power.
  we need to delete these bullets that have disappeared, otherwise the game will do more and more meaningless work and become slower and slower. To this end, we need to detect the condition that the bottom attribute of rect of the bullet is zero, and its table name bullet has passed through the top of the screen:

import sys
import pygame
from settings import Settings
from ship import Ship
import game_functions as gf
from pygame.sprite import Group

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 a spaceship
    ship = Ship(ai_settings, screen)
    # Create a group for storing bullets
    bullets = Group()
    # Start the main cycle of the game
    while True:
        # Monitor keyboard and mouse events
        gf.check_events(ai_settings, screen, ship, bullets)
        ship.update()
        # Redraw the screen each time you cycle
        bullets.update()
        # Delete lost bullets
        for bullet in bullets.copy():
            if bullet.rect.bottom <= 0:
                bullets.remove(bullet)
        print(len(bullets))
        gf.update_screen(ai_settings, screen, ship, bullets)
run_game()

    in the for loop, entries should not be deleted from the list or editing group, so you must traverse the copy of the group. We use the method copy() to set the for loop, which allows us to modify bullets in the loop. We check each bullet to see if it has disappeared from the top of the screen. If so, it will be deleted from bullets. Finally, we use a print statement to show how many bullets we currently have, so as to verify that the disappeared bullets have indeed been deleted.
  if there is no problem with these codes, when we view the terminal window after firing bullets, we will find that the number of bullets will gradually decrease to 0 as bullets disappear at the top of the screen one by one After running the game and confirming that the bullet has been deleted, delete the print statement. If we leave this statement, the game speed will be greatly reduced, because it takes more time to write the output to the terminal than to draw the graphics to the game window.

6. Limit the number of bullets

  many shooting games limit the number of bullets that can appear on the screen at the same time to encourage players to shoot with goals. Let's make such restrictions in the game alien invasion.
  first, in settings The maximum number of bullets allowed to be stored in py:

class Settings():
    """Store all settings classes of alien invasion"""
    def __init__(self):
        """Initialize game settings"""
        # Screen settings
        self.screen_width = 900
        self.screen_height = 600
        self.bg_color = (230, 230, 230)
        # Spacecraft settings
        self.ship_speed_factor = 1.5
        # Bullet settings
        self.bullet_speed_factor = 1
        self.bullet_width = 3
        self.bullet_height = 15
        self.bullet_color = 60, 60, 60
        self.bullets_allowed = 3

  this limits the number of bullets that have not disappeared to three. In game_functions.py check_ keydown_ In events(), we check whether the number of bullets that have not disappeared is less than this setting before creating a new bullet:

import sys
import pygame
from bullet import Bullet
def check_keydown_events(event, ai_settings, screen, ship, bullets):
    """Response key"""
    if event.key == pygame.K_RIGHT:
        ship.moving_right = True
    elif event.key == pygame.K_LEFT:
        ship.moving_left = True
    elif event.key == pygame.K_SPACE:
        # Create a bullet and add it to the group 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):
    """Response release"""
    if event.key == pygame.K_RIGHT:
        ship.moving_right = False
    elif event.key == pygame.K_LEFT:
        ship.moving_left = False
def check_events(ai_settings, screen, ship, bullets):
    """Respond to key and mouse events"""
    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, bullets):
    """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()
    # Make recently drawn screens visible
    pygame.display.flip()

  when players press the spacebar, we check the length of bullets. If len(bullets) is less than 3, we create a new bullet; But if there are three bullets that have not disappeared, nothing will happen when the player presses the spacebar. If you run this game now, there can only be 3 bullets on the screen at most.

7. Create function update_bullets()

  after writing and checking the bullet management code, you can move it to the module game_functions to make the main program file alien_invasion.py as simple as possible. We create a file called update_bullets and add it to the game_ function. End of Py:

import sys
import pygame
from bullet import Bullet
def check_keydown_events(event, ai_settings, screen, ship, bullets):
    """Response key"""
    if event.key == pygame.K_RIGHT:
        ship.moving_right = True
    elif event.key == pygame.K_LEFT:
        ship.moving_left = True
    elif event.key == pygame.K_SPACE:
        # Create a bullet and add it to the group 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):
    """Response release"""
    if event.key == pygame.K_RIGHT:
        ship.moving_right = False
    elif event.key == pygame.K_LEFT:
        ship.moving_left = False
def check_events(ai_settings, screen, ship, bullets):
    """Respond to key and mouse events"""
    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, bullets):
    """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()
    # Make recently drawn screens visible
    pygame.display.flip()
def update_bullets(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)

  update_ The code for bullets () is from alien_invasion.py is cut and pasted. It only needs one parameter, namely grouping bullets.
  alien_ invasion. The while loop in py becomes simpler:

import sys
import pygame
from settings import Settings
from ship import Ship
import game_functions as gf
from pygame.sprite import Group

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 a spaceship
    ship = Ship(ai_settings, screen)
    # Create a group for storing bullets
    bullets = Group()
    # Start the main cycle of the game
    while True:
        # Monitor keyboard and mouse events
        gf.check_events(ai_settings, screen, ship, bullets)
        ship.update()
        gf.update_bullets(bullets)
        gf.update_screen(ai_settings, screen, ship, bullets)
run_game()

  we let the main loop contain as little code as possible, so that we can quickly know what happens in the game by looking at the function name. The main loop checks the player's input, and then updates the ship's position and the position of all bullets that have not disappeared. Next, we use the updated location to draw a new screen.

8. Create function fire_bullet()

   next, move the code for firing bullets to a separate function. In this way, check_keydown_events() uses only one line of code to fire bullets, making the elif code block very simple:

import sys
import pygame
from bullet import Bullet
def check_keydown_events(event, ai_settings, screen, ship, bullets):
    """Response key"""
    if event.key == pygame.K_RIGHT:
        ship.moving_right = True
    elif event.key == pygame.K_LEFT:
        ship.moving_left = True
    elif event.key == pygame.K_SPACE:
        # Create a bullet and add it to the group bullets
        fire_bullet(ai_settings, screen, ship, bullets)
def fire_bullet(ai_settings, screen, ship, bullets):
    """If the limit is not reached, fire a bullet"""
    if len(bullets) < ai_settings.bullets_allowed:
        new_bullet = Bullet(ai_settings, screen, ship)
        bullets.add(new_bullet)
def check_keyup_events(event, ship):
    """Response release"""
    if event.key == pygame.K_RIGHT:
        ship.moving_right = False
    elif event.key == pygame.K_LEFT:
        ship.moving_left = False
def check_events(ai_settings, screen, ship, bullets):
    """Respond to key and mouse events"""
    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, bullets):
    """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()
    # Make recently drawn screens visible
    pygame.display.flip()
def update_bullets(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)

  function fire_bullets only contain the code used to launch bullets when the player presses the spacebar; In check_ keydown_ In events (), we call fire when the player presses the spacebar_ bullet(). We run alien again_ invasion. Py, make sure there is still no error when firing the bullet.

summary

  Last article , we introduced the left-right movement of the spacecraft, the configuration of the corresponding spacecraft speed and the corresponding restrictions on the motion range of the spacecraft. Finally, check the method_ The events method is reconstructed; And a brief summary of several recent documents is made. This paper realizes the Bullet shooting function of the spacecraft; It mainly includes adding Bullet settings, creating Bullet class, storing bullets in the group, firing, deleting disappeared bullets and limiting the number of bullets. Finally, in the game_function.py creates two new functions to further simplify alien_invasion.py. So far, the armed spacecraft, the first big module in our alien invasion, has been introduced to you. We have introduced this function in detail through four articles. Because the effect of this project is dynamic, we can't take a screenshot. If you are interested, you can use the code involved in this function to see the dynamic effect of this module. In order to make you better absorb the knowledge points used in the project, each article only gives you a function of alien invasion. Therefore, I hope you can read it carefully, write the code carefully, understand the in-depth meaning, and maximize the value of the 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.

Topics: Python