Create player missile manager and player missile class in Pygame

In this article we will create two classes that will assist the player object to launch missile, they are a player missile class which serves as the missile object and a missile manager class which will manage all the missiles that player has launched. We will tune up these classes later on when the project goes on but for now lets create these two simple classes first.

First is the missile class.

from pygame import math as mt

class Missile(object):

    def __init__(self, missile_surface, x, y):
        self.on = True
        self.missile_surface = missile_surface
        self.x = x
        self.y = y
        self.missile_pos = mt.Vector2(self.x, self.y)

    def update(self):
        self.y -= 1
        self.missile_pos = mt.Vector2(self.x, self.y)

The above class has a update method which will update the position of the missile on every game loop. Now lets create the missile manager class.

from Missile import Missile

class MissileManager(object):

    def __init__(self, game_sprite):
        self.missile_count = 10
        self.game_sprite = game_sprite
        self.missile_list = []

    def create_missile(self, x, y):
        if(self.missile_count >= 0):
            self.missile_surface = self.game_sprite.getImage()
            self.missile_list.append(Missile(self.missile_surface, x, y))
            self.missile_count -= 1

    def check_boundary(self):
        for i in range(len(self.missile_list)):
            if (self.missile_list[i].y < 0):
                self.missile_list[i].on = False

    def missile_update(self):

        for item in list(self.missile_list):
            if(item.on == False):
                self.missile_list.remove(item)
                self.missile_count += 1
            else:
                item.update()

    def get_missile_list(self):
        return self.missile_list

The missile manager class above has four methods, the create missile method will be called every time the player press the spacebar, but before the missile can be created the method will first check and make sure the total missile quantity on the game scene will not exceed a certain amount which is controls by the missile_count variable. After a missile has been created, that missile will then get pushed into a missile list. Each time a missile has been created the total of the missile_count variable will be reduced by one.

The check boundary method will check to see whether a missile has crossed the top game scene boundary or not, if it has then the missile’s on variable will be switched to False.

The missile update method will loop through each missile in the missile list, if the on variable is set to False then that missile will be removed. Each time a missile has been removed the total of the missile_count variable will be increased by one so we can create a new missile again.

The last method is uses to get the updated missile list object which will be used in the main file.

A few changes have been made in the main file, we have called the missile manager class in this main file to create a new missile and update it’s position, besides that we also create a time counter so we will slow down the missile launch process as well as a new missile rectangle object which will be needed in the GameSprite object. After we have called the scene object to blit so many objects on the game scene the code indeed looks little bit unorganized but don’t worry because we will create a new Game Manager object which we can use on the main file that will organize all those game objects.

import sys, pygame
from pygame import math as mt
from pygame.locals import *
from GameSprite import GameSprite
from BgSprite import BgSprite
from MissileManager import MissileManager

pygame.init()

# game asset url
player_sprite = 'Asset/player.png'
bg_sprite = 'Asset/bg.png'
missile_sprite = 'Asset/missile.png'

player_width = 40
player_height = 40

size = width, height = 660, 660
pygame.display.set_caption("Air Strike") # set the title of the window
screen = pygame.display.set_mode(size)

rect_background = Rect(0, 0, player_width, player_height)  # the rectangle object uses to clip the sprite area
game_sprite = GameSprite(player_sprite, rect_background)
game_sprite_surface = game_sprite.getImage()  # get the player sprite surface

pygame.display.set_icon(game_sprite_surface) # use the same player surface object as the icon for the game window

rect_background = Rect(0, 0, 660, 660)
game_bg_sprite = BgSprite(bg_sprite, rect_background)
game_bg_surface = game_bg_sprite.getImage()  # get the background sprite surface

missile_width = 20
missile_height = 20
rect_missile = Rect(0, 0, missile_width, missile_height)

pygame.mixer_music.load('Music/winternight.ogg')
pygame.mixer_music.play(-1)

player_pos = mt.Vector2(width/2, height/2) # initialize the position of the player sprite

player_draw_pos = mt.Vector2(player_pos.x , player_pos.y)
bg_draw_pos = mt.Vector2(0 , 0)

# player logic variables
speed_x = 0.1
speed_y = 0.1
MOVE_RIGHT = 1
MOVE_LEFT = 2
MOVE_UP = 3
MOVE_DOWN = 4
direction_x = 0
direction_y = 0
strike = False
strike_again = 0

#initialize MissileManager object
missile_game_sprite = GameSprite(missile_sprite, rect_missile)
missile_manager = MissileManager(missile_game_sprite)
missile_list_array = None

while True:

    for event in pygame.event.get():

        if event.type == pygame.QUIT:
            pygame.mixer_music.stop()
            sys.exit()

        # detect key press event for the up, down, left and the right key
        if event.type == KEYDOWN:

            if event.key == K_LEFT:
                direction_x = MOVE_LEFT
            elif event.key == K_RIGHT:
                direction_x = MOVE_RIGHT

            if event.key == K_UP:
                direction_y = MOVE_UP
            elif event.key == K_DOWN:
                direction_y = MOVE_DOWN

            if event.key == K_SPACE:
                strike = True
                strike_again += 1

        elif event.type == KEYUP:
            if event.key == K_LEFT:
                direction_x = 0
            elif event.key == K_RIGHT:
                direction_x = 0

            if event.key == K_UP:
                direction_y = 0
            elif event.key == K_DOWN:
                direction_y = 0

            if event.key == K_SPACE:
                strike = False

    # set new position and detect the boundary of the game scene
    if (direction_x == MOVE_LEFT):
        if(player_pos.x > 0):
            player_pos.x -= speed_x
    elif (direction_x == MOVE_RIGHT):
        if(player_pos.x + player_width < width):
            player_pos.x += speed_x

    if (direction_y == MOVE_UP):
        if (player_pos.y > 0):
            player_pos.y -= speed_y
    elif (direction_y == MOVE_DOWN):
        if (player_pos.y + player_height < height):
            player_pos.y += speed_y

    if(strike == True and strike_again > 1):
        strike_again = 0
        missile_manager.create_missile(player_pos.x + 6, player_pos.y - 8) # create more missile


    player_draw_pos = mt.Vector2(player_pos.x, player_pos.y) # the new vector position of the player

    screen.blit(game_bg_surface, bg_draw_pos)
    screen.blit(game_sprite_surface, player_draw_pos)

    # blit the missile on the scene
    missile_list_array = missile_manager.get_missile_list()
    missile_manager.check_boundary()
    missile_manager.missile_update()

    for i in range(len(missile_list_array)):
        screen.blit(missile_list_array[i].missile_surface, missile_list_array[i].missile_pos)

    pygame.display.flip()

Here is the PyCharm file explorer looks like at the moment.

The new file structure
The new file structure

If you run the above main program you will see this outcome.

That is about it for this article, we will create a Game Manager in the next chapter to organize all the game objects on the scene so the code on the main file will be more organize than present.