Detect the player’s boundary

In this article, we will start to create the boundary detection mechanism which can be used to help the boy moving around the canvas. We will go slowly where this topic will take a few chapters to complete. In this chapter, we will focus on below issues.

  1. The boy will not be able to move past the horizontal boundary of either 0 or 576 pixels which is the physical boundary for the boy sprite.
  2. The boy will be able to move upward or downward but not side-way when he is inside the ladder.
  3. When the boy is inside the ladder his horizontal movement will be disabled so the boy can either move up or down only, we will enable the boy’s horizontal movement again when the boy reaches the top of the ladder in the next chapter.

In order to achieve the above outcomes, we will edit two files. The boy object file will now contain the ladder boundary which will be used to detect whether the boy is inside the ladder or not. Finally, we will edit the boy sprite to link up those mechanisms that we are talking about.

class BoyObject(object):

    def __init__(self):

        self.list_1 = [

            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [1, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
        ]

        self.boundary_1 = [[9 * 64, 8 * 64],
                           [9 * 64, 7 * 64]] # the boundary of the ladder

        self.initial_1 = [0, 8 * 64]

    def get_original_position(self, level):

        if (level == 1):
            return self.initial_1

    def get_object_list(self, level):

        if(level == 1):
            return self.list_1

    def get_object_boundary(self, level):

        if (level == 1):
            return self.boundary_1
from BoyObject import BoyObject
from pygame import math as mt
from pygame.locals import *
from GameSprite import GameSprite

class BoySprite(object):

    def __init__(self, scene, level):

        self.row = 10
        self.column = 10
        self.scene = scene # game scene instance
        self.space = 64 # image width and height
        self.level = level # current game level
        self.frame = 3
        self.prepare_boy(self.level)
        self.WIDTH = 640

    def prepare_boy(self, level):
        self.boy_object = BoyObject()
        self.boy_object_list = self.boy_object.get_object_list(level)
        self.boy_original_position = self.boy_object.get_original_position(level)
        self.x = self.boy_original_position[0]
        self.y = self.boy_original_position[1]
        self.boy_image_sprite_right = 'Asset/bright.png'
        self.boy_image_sprite_left = 'Asset/bleft.png'
        self.boy_sprite = self.boy_image_sprite_right
        self.left = False
        self.up = False
        self.boy_rect = Rect(self.frame * 64, 0, 64, 64)
        self.sprite_boy = GameSprite(self.boy_sprite, self.boy_rect)
        self.boy_surface = self.sprite_boy.getImage()
        self.boy_boundary_list = self.boy_object.get_object_boundary(level)
        self.initialize()

    # set the x and y direction for the player object

    def setX(self, x):
        if(self.up == False):
            self.x += x
            if(x < 0):
                self.left = True
                self.frame += 1

                if (self.frame > 5):
                    self.frame = 1
                self.boy_sprite = self.boy_image_sprite_left
            elif(x > 0):
                self.frame += 1
                self.left = False
                if (self.frame > 4):
                    self.frame = 0
                self.boy_sprite = self.boy_image_sprite_right
            elif(x == 0):
                if(self.left == True):
                    self.frame = 2
                    self.boy_sprite = self.boy_image_sprite_left
                elif(self.left == False):
                    self.frame = 3
                    self.boy_sprite = self.boy_image_sprite_right

            self.boy_rect = Rect(self.frame * 64, 0, 64, 64)
            self.sprite_boy = GameSprite(self.boy_sprite, self.boy_rect)
            self.boy_surface = self.sprite_boy.getImage()

    def setY(self, y):
        if(self.up == True):
            self.y += y
            if(y == 0 or self.up == False):
                self.frame = 6
            else:
                if(y < 0):
                    self.frame -= 1
                elif(y > 0):
                    self.frame += 1
                if(self.frame > 10):
                    self.frame = 6
                elif(self.frame < 6):
                    self.frame += 2
            self.boy_sprite = self.boy_image_sprite_right
            self.boy_rect = Rect(self.frame * 64, 0, 64, 64)
            self.sprite_boy = GameSprite(self.boy_sprite, self.boy_rect)
            self.boy_surface = self.sprite_boy.getImage()

    def checkboundary(self):
        if(self.x < 0):
            self.x = 0
        elif(self.x > self.WIDTH - self.space):
            self.x = self.WIDTH - self.space 
        else:
            for boundary in self.boy_boundary_list:
                boundary_rect = Rect(boundary[0], boundary[1], 64, 64)
                if(boundary_rect.collidepoint(self.x, self.y) == True):
                    self.up = True

    def update(self):
        self.move_boy()
        self.checkboundary()

    def move_boy(self):
        self.draw_pos = mt.Vector2(self.x, self.y)  # the position of the image on game scene

    def initialize(self):
        for row in range(self.row):
            for column in range(self.column):

                if(self.boy_object_list[row][column] == 1):

                    self.draw_pos = mt.Vector2(self.x, self.y)  # the position of the image on game scene
                    self.scene.blit(self.boy_surface, self.draw_pos)  # draw enemy frame

    def draw(self):

        self.scene.blit(self.boy_surface, self.draw_pos)  # draw enemy frame

If you run the program again this is what you will see.

Alright, in the next chapter we will continue to modify the boundary detection mechanism for the boy.

Complete rewrites of the level manager class

In this chapter, we will rewrite the level manager class by deleting old functions and adding new functions into it. Besides that, we will also use the pickle file to replace the text file then save the game level in the form of a list instead of a separate number. The previous method which saves each level as a number in the text file has introduced some bugs into the program that appear when the start scene class wants to retrieve those levels from the text file to display them on the score page. With pickle file replacing the text file we have fixed those bugs once and for all. The level manager class will now handle all the level saving and retrieving processes that have previously share among a few classes.

In order to save the level list in the byte format in a pickle file, we will import the pickle module into the level manager class.

import pickle

class LevelManager(object):

    def __init__(self, gm):

        self.game_manager = gm
        self.delete_line = False
        self.MAX_LEVEL = 3
        self.level = 1
        self.level_list = []

    def set_level(self):

        try:

            f = open("level.pickle", "rb")
            self.level_list = pickle.load(f)
            self.level = self.level_list[len(self.level_list) - 1]
            if (len(self.level_list) > 5):
                self.level_list.pop(0)

        except EOFError:
            self.level = 1
            self.level_list.append(self.level)

    def save_level(self):
        try:
            self.level_list.append(self.level)
            if(len(self.level_list) > 5):
                self.level_list.pop(0)
            f = open("level.pickle", "wb")
            pickle.dump(self.level_list, f)
            f.close()
        except IOError:
            print('cannot open a file')

    def increase_level(self):

        self.level += 1
        if(self.level >  self.MAX_LEVEL):
            self.game_manager.state = self.game_manager.WIN
            self.level = 1
            self.game_manager.setup(self.level)
        else:
            self.game_manager.state = self.game_manager.NEXT
            self.game_manager.setup(self.level)

    def get_level(self):

        return self.level

    def get_list(self):

        return self.level_list

As you can see, we have limited the level list to only five elements as before. We will also need to create an empty pickle file in the same directory with the other project classes just like how we had created the text file in the previous chapter. We can remove the unused text file now from the same directory.

level.pickle

Now we will be able to call the save_level method to save the current game level when we need it.

Below is the remaining classes that we need to edit to suite the above changes.

from BgSprite import BgSprite
from GameSprite import GameSprite
from pygame.locals import *
from pygame import math as mt
import pygame
import pygame.font as txt
from AirStrikeColor import AirStrikeColor

class StartScene(object):

    def __init__(self, scene, lm):

        self.level_manager = lm

        self.scene = scene
        self.play_button = 'Asset/play.png'
        self.about_button  = 'Asset/about.png'
        self.exit_button = 'Asset/exit.png'
        self.scene_button = 'Asset/scene.png'
        self.score_button = 'Asset/score.png'
        self.home_button = 'Asset/back.png'
        self.button_image = 'Asset/button_play.png'
        self.manual_button = 'Asset/manual.png'
        self.bg_image = 'Asset/start.png'
        self.win_image = 'Asset/winn.png'
        self.general_image = 'Asset/general.png'


        self.soundon = 'Asset/sound.png'
        self.soundoff = 'Asset/soundoff.png'
        self.home_button_image = 'Asset/home.png'
        self.game_logo = 'Asset/enemy3.png'
        self.bg_rect = Rect(0, 0, 660, 660)
        self.button_rect = Rect(0, 0,  306, 112)
        self.home_button_rect = Rect(0, 0, 200, 53)
        self.back_button_rect = Rect(0, 0, 40, 30)
        self.sound_button_rect = Rect(0, 0, 30, 30)
        self.game_logo_rect = Rect(0, 0, 160, 160)

        self.sprite = BgSprite(self.general_image, self.bg_rect)


        self.sprite_win = BgSprite(self.win_image, self.bg_rect)

        self.sprite_pause = BgSprite(self.general_image, self.bg_rect)

        self.soundon_button = GameSprite(self.soundon, self.sound_button_rect)
        self.soundoff_button = GameSprite(self.soundoff, self.sound_button_rect)

        self.soundoff_button_surface = self.soundoff_button.getImage()  # get the button sprite surface
        self.soundon_button_surface = self.soundon_button.getImage()  # get the button sprite surface
        self.game_logo_sprite = GameSprite(self.game_logo, self.game_logo_rect)
        self.sprite_button = GameSprite(self.button_image, self.button_rect)
        self.sprite_home_pause_button = GameSprite(self.home_button_image, self.home_button_rect)
        self.sprite_scene_button = GameSprite(self.scene_button, self.home_button_rect)
        self.sprite_manual_button = GameSprite(self.manual_button, self.home_button_rect)
        self.sprite_exit_button = GameSprite(self.exit_button, self.home_button_rect)
        self.sprite_play_button = GameSprite(self.play_button, self.home_button_rect)
        self.sprite_about_button = GameSprite(self.about_button, self.home_button_rect)
        self.sprite_score_button = GameSprite(self.score_button, self.home_button_rect)
        self.sprite_home_button = GameSprite(self.home_button, self.back_button_rect)


        self.win_surface = self.sprite_win.getImage()  # get the win sprite surface
        self.pause_surface = self.sprite_pause.getImage()  # get the pause sprite surface
        self.surface = self.sprite.getImage()  # get the start scene sprite surface
        self.button_surface = self.sprite_button.getImage() # get the button sprite surface
        self.home_pause_button_surface = self.sprite_home_pause_button.getImage() # get the button sprite surface
        self.play_button_surface = self.sprite_play_button.getImage()  # get the button sprite surface
        self.about_button_surface = self.sprite_about_button.getImage()  # get the button sprite surface
        self.score_button_surface = self.sprite_score_button.getImage()  # get the button sprite surface
        self.manual_button_surface = self.sprite_manual_button.getImage()  # get the button sprite surface
        self.scene_button_surface = self.sprite_scene_button.getImage()  # get the button sprite surface
        self.home_button_surface = self.sprite_home_button.getImage()  # get the button sprite surface
        self.exit_button_surface = self.sprite_exit_button.getImage()  # get the button sprite surface
        self.game_logo_surface = self.game_logo_sprite.getImage() # get game logo image
        self.draw_pos = mt.Vector2(0, 0)
        self.draw_button_pos = mt.Vector2(177, 274)
        self.draw_game_logo_pos = mt.Vector2(249, 100)
        self.draw_play_button_pos = mt.Vector2(229, 200)
        self.draw_about_button_pos = mt.Vector2(229, 263)
        self.draw_home_button_pos = mt.Vector2(229, 263)
        self.draw_score_button_pos = mt.Vector2(229, 328)
        self.draw_manual_button_pos = mt.Vector2(229, 393)
        self.draw_exit_button_pos = mt.Vector2(229, 456)
        self.draw_scene_button_pos = mt.Vector2(229, 519)
        self.draw_back_button_pos = mt.Vector2(10, 620)

        self.draw_sound_button_pos = mt.Vector2(10, 620)

        self.soundon = True
        self.count = 0

        self.font = txt.Font('Asset/ft.ttf', 90)
        self.credit_font = txt.Font('Asset/ft.ttf', 50)
        self.score_text = "Top Achievements"
        self.credit_text_i = "Create by : IslandTropicalMan"
        self.over_text_i = "Game Over"
        self.next_text_i = "Next Level"
        self.text_width, self.text_height = self.font.size(self.score_text)
        self.credit_text_width, self.credit_text_height = self.credit_font.size(self.credit_text_i)
        self.over_text_width, self.over_text_height = self.credit_font.size(self.over_text_i)
        self.next_text_width, self.next_text_height = self.credit_font.size(self.next_text_i)
        self.x_title = 330 - self.text_width/2
        self.x_credit = 330 - self.credit_text_width/2
        self.x_over = 330 - self.over_text_width / 2
        self.x_next = 330 - self.next_text_width/2
        self.y_title = 60
        self.title_rect = Rect(self.x_title, self.y_title, self.text_width, self.text_height)
        self.title_score_text = self.font.render(self.score_text, 1, (255, 255, 255))
        self.credit_rect = Rect(self.x_credit, 330, self.credit_text_width, self.credit_text_height)
        self.over_rect = Rect(self.x_over, 190, self.over_text_width, self.over_text_height)
        self.next_rect = Rect(self.x_next, 190, self.next_text_width, self.next_text_height)
        self.credit_text = self.credit_font.render(self.credit_text_i, 1, (255, 255, 255))
        self.over_text = self.credit_font.render(self.over_text_i, 1, (255, 255, 255))
        self.next_text = self.credit_font.render(self.next_text_i, 1, (255, 255, 255))
        self.score_value_text = ''
        self.f1 = None
        self.font1 = txt.Font('Asset/ft.ttf', 100)
        self.score_rect = Rect(100, self.y_title+self.text_height, 100, 100)
        self.home_background_color = AirStrikeColor(0, 0, 0, 255)

    def draw(self, state):

        if(state == 0):
            self.scene.fill(self.home_background_color)
            self.scene.blit(self.game_logo_surface, self.draw_game_logo_pos) # draw a game logo
            self.scene.blit(self.play_button_surface, self.draw_play_button_pos)  # draw a button sprite
            self.scene.blit(self.about_button_surface, self.draw_about_button_pos)  # draw a button sprite
            self.scene.blit(self.score_button_surface, self.draw_score_button_pos)  # draw a button sprite
            self.scene.blit(self.manual_button_surface, self.draw_manual_button_pos)  # draw a button sprite
            self.scene.blit(self.exit_button_surface, self.draw_exit_button_pos)  # draw a button sprite
            self.scene.blit(self.scene_button_surface, self.draw_scene_button_pos)  # draw a button sprite
            if(self.soundon == True):
                self.scene.blit(self.soundon_button_surface, self.draw_sound_button_pos)  # draw a button sprite
            else:
                self.scene.blit(self.soundoff_button_surface, self.draw_sound_button_pos)  # draw a button sprite
        elif(state == 2):

            self.scene.fill(self.home_background_color)
            self.scene.blit(self.over_text, self.over_rect)  # the over text

        elif (state == 3):

            self.scene.fill(self.home_background_color)
            self.scene.blit(self.next_text, self.next_rect)  # the next text

        elif(state == 4):
            self.scene.blit(self.win_surface, self.draw_pos)  # draw a win sprite

        elif (state == 5):
            self.scene.fill(self.home_background_color) # draw a background
            self.scene.blit(self.credit_text, self.credit_rect)  # the credit text
            #self.scene.blit(self.about_surface, self.draw_pos)  # draw a about sprite
            self.scene.blit(self.home_button_surface, self.draw_back_button_pos)  # draw a button sprite

        elif (state == 6):
            self.scene.blit(self.manual_surface, self.draw_pos)  # draw a manual sprite
            self.scene.blit(self.home_button_surface, self.draw_back_button_pos)  # draw a button sprite

        elif (state == 7):
            #self.scene.blit(self.pause_surface, self.draw_pos)  # draw a pause sprite
            self.scene.fill(self.home_background_color)  # draw a background
            self.scene.blit(self.play_button_surface, self.draw_play_button_pos)  # draw a button sprite
            self.scene.blit(self.home_pause_button_surface, self.draw_home_button_pos)  # draw a button sprite

        elif (state == 8):

            self.scene.fill(self.home_background_color)  # draw a background
            self.scene.blit(self.title_score_text, self.title_rect) # the score title first
            list_level = self.level_manager.get_list()

            for i in range(len(list_level)):
                self.score_rect = Rect(95, self.y_title + self.text_height + self.count * 100, 100, 100)
                self.score_value_text = str(self.count+1) + ".) Level " + str(list_level[i])
                self.value_score_text = self.font1.render(self.score_value_text, 1, (255, 255, 255))
                self.scene.blit(self.value_score_text, self.score_rect)  # the top 5 levels of the game
                self.count += 1

            self.count = 0

            self.scene.blit(self.home_button_surface, self.draw_back_button_pos)  # draw a button sprite

        if(state == 2 or state == 3 or state == 4):
            self.scene.blit(self.button_surface, self.draw_button_pos)  # draw a button sprite

        pygame.display.flip()
from Player import Player
from Background import Background
from EnemyManager import EnemyManager
from Overlap import Overlap
from ExplosionManager import ExplosionManager
from Score import Score
from StartScene import StartScene
from pygame.locals import *
from LevelManager import LevelManager
import pygame
import webbrowser
from Scene import Scene

class GameManager(object):

    def __init__(self, scene):

        self.scene = scene

        self.load_music()
        self.play_music()
        self.overlap_manager = Overlap()
        self.level_manager = LevelManager(self)
        self.level_manager.set_level()
        self.setup(self.level_manager.get_level())
        self.start_scene = StartScene(scene, self.level_manager)
        #self.setup(3)

        self.pause = False # flag to pause the game

        self.game_scene = Scene(self.scene)

        #game state
        self.LOAD = 0
        self.GAME = 1
        self.OVER = 2
        self.NEXT = 3
        self.WIN = 4
        self.ABOUT = 5
        self.MANUAL = 6
        self.PAUSE = 7
        self.SCORE = 8
        self.SCENE = 9

        self.state = self.LOAD

    def setup(self, game_level):

        self.game_level = game_level
        self.score_manager = Score(self.scene)
        self.background = Background(self.scene)
        self.player = Player(self.scene)
        self.enemy_manager = EnemyManager(self.scene, self.player, game_level)
        self.explosion_manager = ExplosionManager(self.scene)

    def loop(self):

        if(self.state == self.LOAD):
            self.start_scene.draw(self.state)
        elif(self.state == self.OVER or self.state == self.NEXT or self.state == self.WIN or self.state == self.ABOUT or self.state == self.MANUAL or self.state == self.SCORE):
            self.start_scene.draw(self.state)
        elif(self.state == self.SCENE):
            self.game_scene.draw()
        elif(self.state == self.GAME):

            self.update()
            self.draw()

        elif(self.state == self.PAUSE):

            self.start_scene.draw(self.state)

    def isAreaClick(self, x, y):
        if (self.state == self.LOAD or self.state == self.OVER or self.state == self.NEXT or self.state == self.WIN or self.state == self.ABOUT or self.state == self.SCORE or self.state == self.SCENE or self.state == self.MANUAL or self.state == self.PAUSE):
            self.rect = Rect(177, 274, 306, 112) # the position of the play button on the scene
            self.rect_play = Rect(229, 200, 200, 53)  # the position of the play button on the home scene
            self.rect_about = Rect(229, 263, 200, 53)  # the position of the about button on the home scene
            #self.rect_exit = Rect(229, 456, 200, 53)  # the position of the exit button on the home scene
            self.rect_pause_home = Rect(229, 263, 200, 53)  # the position of the home button on pause scene
            self.rect_score = Rect(229, 328, 200, 53)  # the position of the score button on the home scene
            self.rect_manual = Rect(229, 393, 200, 53)  # the position of the manual button on the home scene
            self.rect_scene = Rect(229, 519, 200, 53)  # the position of the manual button on the home scene
            self.rect_back = Rect(10, 620, 40, 30)  # the position of the back button on the home scene
            self.rect_sound = Rect(10, 620, 30, 30) # the position of the sound button on the home scene
            self.rect_scene_next = Rect(610, 330, 30, 30)  # the position of the next scene button on scene
            self.rect_scene_previous = Rect(50, 330, 30, 30)  # the position of the previous scene button on scene

            if(self.rect.collidepoint(x, y) and (self.state == self.OVER or self.state == self.NEXT or self.state == self.WIN)):
                self.state = self.GAME
            elif(self.rect_play.collidepoint(x,y) and self.state == self.LOAD):
                self.state = self.GAME
            elif (self.rect_play.collidepoint(x, y) and self.state == self.PAUSE):
                self.state = self.GAME
            elif (self.rect_about.collidepoint(x, y) and self.state == self.LOAD):
                self.state = self.ABOUT
            elif (self.rect_score.collidepoint(x, y) and self.state == self.LOAD):
                self.state = self.SCORE
            elif (self.rect_scene.collidepoint(x, y) and self.state == self.LOAD):
                self.state = self.SCENE
            elif (self.rect_back.collidepoint(x, y) and self.state == self.SCENE):
                self.state = self.LOAD
            elif (self.rect_scene_next.collidepoint(x, y) and self.state == self.SCENE):
                self.game_scene.set_next_image()
            elif (self.rect_scene_previous.collidepoint(x, y) and self.state == self.SCENE):
                self.game_scene.set_previous_image()
            elif (self.rect_pause_home.collidepoint(x, y) and self.state == self.PAUSE):

                self.state = self.LOAD
                self.setup(self.level_manager.get_level())
                self.save_level()

            elif (self.rect_manual.collidepoint(x, y) and self.state == self.LOAD):
                webbrowser.open_new('http://gamingdirectional.com/blog/2018/12/25/air-strike//')
            elif (self.rect_back.collidepoint(x, y) and (self.state == self.ABOUT or self.state == self.MANUAL or self.state == self.SCORE)):
                self.state = self.LOAD
            elif (self.rect_sound.collidepoint(x, y) and self.state == self.LOAD):

                if(self.start_scene.soundon == True):
                    self.start_scene.soundon = False
                    pygame.mixer_music.pause()
                else:
                    self.start_scene.soundon = True
                    pygame.mixer_music.unpause()

    def save_level(self):
       self.level_manager.save_level()

    def set_pause(self, pause):

        self.pause = pause

        if(self.pause == True):

            self.state = self.PAUSE

    def load_music(self):
        pygame.mixer_music.load('Music/winternight.ogg')

    def play_music(self):
        pygame.mixer_music.play(-1) #play the music infinite time

    def set_player_x(self, _x):
        if (self.state == self.GAME):
            self.player.setX(_x)

    def save_scene(self):
        self.game_scene.take_screen()

    def set_player_y(self, _y):
        if (self.state == self.GAME):
            self.player.setY(_y)

    def set_missile_strike(self, strike):
        if (self.state == self.GAME):
            self.player.setStrike(strike)

    def update(self):
        self.player.update()
        self.enemy_manager.update()
        self.isOverlap()
        self.explosion_manager.explosion_update()

    # check for player, enemy, missiles overlap
    def isOverlap(self):
        self.overlap_manager.isOverlap(self.player, self.enemy_manager, self.explosion_manager, self.score_manager, self)

    def draw(self):
        if(self.state == self.GAME):
            self.background.draw()
            self.player.draw()
            self.enemy_manager.draw()
            self.explosion_manager.draw()
            self.score_manager.draw()
            pygame.display.flip()

Besides that, we will also need to edit the main file to call the save_level method from the game manager class which will then call the method with the same name from the level manager class to save the current game level when the player exits the game.

import pygame
from pygame.locals import *
from GameManager import GameManager

pygame.init()

size = width, height = 660, 660
pygame.display.set_caption("Air Strike")  # set the title of the window
screen = pygame.display.set_mode(size)
game_manager = GameManager(screen)
rect_exit = Rect(229, 456, 200, 53)  # the position of the exit button on the home scene
running = True

while running:

    for event in pygame.event.get():

        if event.type == pygame.QUIT:
            game_manager.save_level()
            running = False
        # detect key press event
        if event.type == KEYDOWN:

            if (game_manager.state == 1):
                if event.key == K_LEFT:
                    game_manager.set_player_x(-0.1)
                elif event.key == K_RIGHT:
                    game_manager.set_player_x(0.1)

                if event.key == K_UP:
                    game_manager.set_player_y(-0.1)
                elif event.key == K_DOWN:
                    game_manager.set_player_y(0.1)

                if event.key == K_SPACE:
                    game_manager.set_missile_strike(True)

                if event.key == K_p:
                    game_manager.set_pause(True)  # set the pause state to true

                if event.key == K_s:
                    game_manager.save_scene()

        elif event.type == KEYUP:

            if (game_manager.state == 1):
                if event.key == K_LEFT:
                    game_manager.set_player_x(0)
                elif event.key == K_RIGHT:
                    game_manager.set_player_x(0)

                if event.key == K_UP:
                    game_manager.set_player_y(0)
                elif event.key == K_DOWN:
                    game_manager.set_player_y(0)

                if event.key == K_SPACE:
                    game_manager.set_missile_strike(False)

        elif event.type == pygame.MOUSEBUTTONDOWN:
            x, y = event.pos
            if (rect_exit.collidepoint(x, y) and game_manager.state == game_manager.LOAD):
                game_manager.save_level()
                running = False
            # 1 is the left mouse button
            elif event.button == 1:
                game_manager.isAreaClick(x, y)

    game_manager.loop()

The old version of the game is ready for download, the new version of the game will be uploaded to the major gaming sites once it is ready.

Download Air Strike

The next pygame maze project will start shortly in a few days time so stay tuned.

Move the enemy ship up and down

Hello and welcome back, in this article we will create a mechanism to move the horizontal moving enemy ship up and down within a certain vertical range. It will be very boring if the horizontal moving enemy can only move from side to side only, thus by including the vertical movement of the enemy ship will improve the quality of the entire game.

In order to move the enemy ship within a certain vertical range we will need to edit the enemy1 class accordingly by including a switch to control the up and down movement of the enemy ship.

from pygame import math as mt
from Objectpool import Objectpool

class Enemy1(object):

    def __init__(self, enemy_surface, x, y):

        self.on = True
        self.enemy_surface = enemy_surface
        self.x = x
        self.y = y
        self.hit = False
        self.direction = True
        self.y_direction = True
        self.enemy_pos = mt.Vector2(self.x, self.y)
        self.missile_count = 10
        self.missile_timer = 0
        self.missile_object_pool = Objectpool(self.missile_count)
        self.missile_list = []

    def update(self):

        if(self.direction == True):
            self.x += 0.1
        else:
            self.x -= 0.1

        if(self.y >= 160 and self.y_direction == True):
            self.y -= 0.1
        elif (self.y <= 250 and self.y_direction == False):
            self.y += 0.1

        if (self.y < 160):
            self.y_direction = False
        elif(self.y > 250):
            self.y_direction = True

        self.enemy_pos = mt.Vector2(self.x, self.y)
        self.missile_update(self.missile_object_pool)

    def missile_update(self, pool):

        for item in list(self.missile_list):
            if (item.on == False):
                self.missile_list.remove(item)
                pool.recycle(item)
            else:
                item.update()

    def missile_draw(self, scene): # draw enemy missiles on game scene
        for item in list(self.missile_list):
            scene.blit(item.missile_surface, item.missile_pos)


    def create_enemy_missile(self, enemy_missile_manager):

        if(self.missile_timer > 300):

            self.missile_timer = 0

            if (self.missile_object_pool.getSize() > 0):
                enemy_missile_manager.create_missile(self.x + 3, self.y + 100, self.missile_object_pool, self.missile_list)
                enemy_missile_manager.create_missile(self.x + 50, self.y + 100, self.missile_object_pool, self.missile_list)
                enemy_missile_manager.create_missile(self.x + 100, self.y + 100, self.missile_object_pool, self.missile_list)
            else:
                enemy_missile_manager.create_missile(self.x + 3, self.y + 100, None, self.missile_list)
                enemy_missile_manager.create_missile(self.x + 50, self.y + 100, None, self.missile_list)
                enemy_missile_manager.create_missile(self.x + 100, self.y + 100, None, self.missile_list)

        else:
            self.missile_timer += 1

After you have edited the above enemy class, the horizontal moving enemy ship will be able to move up and down as shown in the below video.

The up and down movement of the enemy ship

The pygame project has finally ready

It has been a day since I had mentioned that I want to upload the new pygame project to the major gaming websites but because of some technical problems that occurred during the files packaging stage the uploading plan has been delayed until today. I have managed to solve all the files packaging issues this morning thus finally this game has been uploaded successfully to various gaming websites. Although we have finished this project together this game is still at its early stage which means more features and levels will be included from time to time. You can download this game from any of these three websites below.

If you have any problem playing the game or installed it on your windows 10 laptop then do let me know through the comment box below this post. With that, we are now fully ready to move into our next python game programming project in the next article.

Summarize the python pygame project

Hello my friend, I just want to let you know that I have packed up the previous pygame project which we have developed together every day and it is now ready to distribute to all the major gaming platforms. If you have missed out any of the tutorials from the past regarding this project then don’t forget to read them all through the below list. You might find out that some classes have changed so often due to the need to do so. Although there are still many new changes happening from time to time that I will not show them to you on this website anymore, I think those classes above are already good enough to get you started on your own pygame project. Below are all the articles that are related to this latest pygame project which we have just finished. Hope you like it.

After we have finished this project, which we already did, we will move on to our next project, the pygame maze project, which is a lot more complicated than this one.

The game is ready for upload

Welcome to the final chapter of this pygame project where we have finally concluded the pygame project which has been ongoing for some time already. In this chapter I have just made a slight modification on the overlap class by reducing the points the player can get when the player missile hits the larger enemy ship.

from pygame.locals import *

class Overlap(object):

    def __init__(self):
        pass # nothing here

    # is player and enemy, player missile, enemy missile overlap
    def isOverlap(self, player, em, ex, score, gm):

        self.checkOverlap(em.enemy_list, player, ex, gm, score, em.width, em.height, em.enemy_missile_manager.width, em.enemy_missile_manager.height, None)

        if(gm.level_manager.get_level() == 3):
            self.checkOverlap(em.horizontal_enemy_list, player, ex, gm, score, em.width1, em.height1, em.enemy_missile_manager.width, em.enemy_missile_manager.height, gm.level_manager.get_level())

    def checkOverlap(self, e_list, player, ex, gm, score, width, height, m_width, m_height, level):

        self.player_rect = Rect(player.pos.x, player.pos.y, player.width, player.height)

        for i in range(len(e_list)):  # is player collides with enemy

            self.em_rect = Rect(e_list[i].x, e_list[i].y, width, height)
            if (self.player_rect.colliderect(self.em_rect)):
                e_list[i].on = False
                if (e_list[i].hit == False):
                    ex.create_explosion(player.pos.x + 2, player.pos.y + 2)
                    e_list[i].hit = True
                    gm.state = gm.OVER
                    gm.setup(gm.level_manager.get_level())

        for i in range(len(e_list)):  # is enemy missile hits player

            for j in range(len(e_list[i].missile_list)):
                self.em_rect = Rect(e_list[i].missile_list[j].x, e_list[i].missile_list[j].y,
                                    m_width, m_height)
                if (self.player_rect.colliderect(self.em_rect)):
                    e_list[i].missile_list[j].on = False
                    ex.create_explosion(player.pos.x + 2, player.pos.y + 2)
                    score.set_score(-1)
                    if (score.power_y > 100):
                        gm.state = gm.OVER
                        gm.setup(gm.level_manager.get_level())

        for i in range(len(e_list)):  # is player missile hits enemy

            self.em_rect = Rect(e_list[i].x, e_list[i].y, width, height)

            for j in range(len(player.getMissileManager().missile_list)):

                self.mm_rect = Rect(player.getMissileManager().missile_list[j].x,
                                    player.getMissileManager().missile_list[j].y, player.getMissileManager().width,
                                    player.getMissileManager().height)

                if (self.em_rect.colliderect(self.mm_rect)):
                    e_list[i].on = False
                    player.getMissileManager().missile_list[j].on = False
                    if (e_list[i].hit == False):
                        ex.create_explosion(e_list[i].x, e_list[i].y + 2)
                        e_list[i].hit = True

                        if(level == 3):
                            score.set_score(2)
                        else:
                            score.set_score(1)
                        if (score.score >= gm.level_manager.get_level() * 30):
                            gm.level_manager.increase_level()

With that we have concluded this final chapter of our pygame project development tutorial and are now ready to start a brand new one a few days from now. This project which we have finished will be uploaded to the online gaming site where you will be able to download the game setup file for your windows os, at the moment this game is built only for the windows os user but if you have followed my previous tutorials on this project then you will be able to easily recreate this game for Linux and osx as well. I will tidy up the game code and recreate the game graphics before uploading this game to any online gaming site, this will be the last chapter regarding this project but need not worry because while I continue developing this game which only has three levels at the moment I will also start a brand new pygame project starting from the next chapter. I will let you guys know where am I uploading this latest project to in the coming article so you can download it to your windows os’s laptop and then play it.

Before we close this final chapter I would like to talk about my incoming development plan for a while. At the beginning I am planning to create a few games using python and the pygame framework, a few JavaFx games and a few android games using Java. But if you are also a Java developer then you should know that Java has gone through some changes lately, myself is a very careful person and I always think before I make any move which might bring me into trouble, thus I have decided to call off the plan to build desktop game based on JavaFx framework because the Java developer may need to pay the Java 11 license fee starting from the year 2019 and I am really not sure will that includes the JavaFx  as well as Java 8 or not. Although I will not use Java 11 but I am still afraid that even Java 8 will be included into the license fees category in the future so I will just stop all the JavaFx game development projects and then see what will come next. As for the android game, the Android Java version is based on Java 6 if I am not mistaken so it should have no impact at all to the Java developer. Thus here is the revised plan: 1) Create 5 python games 2) Create 5 android games (either using Java 6 or unity/c#). 3) Canceled the JavaFx game projects altogether. You might want to say that it is alright for the Java developer to use the open Java sdk to build the application but I don’t want to take any risk because of nobody knows what will happen to the open Java sdk as well in the future.

Alright, so much for that, it is time to get ready for our next pygame project!

Create a pool object for enemy ships

In this article we will start to create a pool object which will recycle the enemy ship and then we will create a new object pool for the missiles on the next article.

Before we can create a pool object we will need to create the Objectpool class first which has two important methods:-

1) Put the enemy ship to an object pool when it gets removed by the enemy list.
2) Return the ship again to the enemy list when the Enemy Manager needs to create a new ship.

Here is the Objectpool class.

class Objectpool(object):

    def __init__(self, size):

        self.size = size
        self.count = 0
        self.elist = [None]*size

    def recycle(self, item):

        if (self.count  < self.size):
            self.elist[self.count] = item
            self.count += 1

    def obtain(self):

        if (self.count > 0):
            self.count -= 1
            self.item = self.elist[self.count]
            self.elist[self.count] = None
            self.item.missile_count = 1
            return self.item

    def getSize(self):

        return self.count

In order to use the object pool class we need to initialize it first and make a few changes in the Enemy Manager class.

from Enemy import Enemy
from GameSprite import GameSprite
from pygame.locals import *
from EnemyMissileManager import EnemyMissileManager
import random
from Objectpool import Objectpool

class EnemyManager(object):

    def __init__(self, scene, player):

        self.enemy_missile_manager = EnemyMissileManager(scene, player)
        self.scene = scene
        self.player = player
        self.enemy_count = 10
        self.enemy_list = []
        self.image = 'Asset/enemy0.png'
        self.width = 30
        self.height = 30
        self.rect = Rect(0, 0, self.width, self.height)
        self.more_enemy = 0
        self.y = -50
        self.boundary_width = 660
        self.boundary_height = 660
        self.object_pool = Objectpool(self.enemy_count)

        # initialize game sprite object
        self.sprite = GameSprite(self.image, self.rect)

    def create_enemy(self, x, y):
        if(self.enemy_count > 0):
            if(self.object_pool.getSize() > 0):
                self.enemy_list.append(self.object_pool.obtain())
            else:
                self.enemy_surface = self.sprite.getImage()
                self.enemy_list.append(Enemy(self.enemy_surface, x, y))
            self.enemy_count -= 1


    def update(self):
        if (self.more_enemy > 600):
            self.more_enemy = 0
            x = random.randint(30, self.boundary_width - 50)
            self.create_enemy(x , self.y)  # create more enemy
        else:
            self.more_enemy += 1 # increase time

        self.enemy_update()
        self.check_boundary()
        self.create_enemy_missile()
        self.enemy_missile_manager.update()

    def create_enemy_missile(self):
        for item in list(self.enemy_list):
            if(item.missile_count > 0):
                if(self.player.pos.y - item.y  < 100 and abs(self.player.pos.x - item.x) < 60 ):
                    self.enemy_missile_manager.create_missile(item.x + 5, item.y + 4)
                    item.missile_count -= 1

    def enemy_update(self):

        for item in list(self.enemy_list):
            if(item.on == False):
                self.enemy_list.remove(item)
                self.enemy_count += 1
                item.y = self.y
                item.on = True
                self.object_pool.recycle(item)
            else:
                item.update()

    def check_boundary(self):
        for i in range(len(self.enemy_list)):
            if (self.enemy_list[i].y > self.boundary_height):
                self.enemy_list[i].on = False

    def draw(self):

        # blit the enemy on  the scene
        for i in range(len(self.enemy_list)):
            self.scene.blit(self.enemy_list[i].enemy_surface, self.enemy_list[i].enemy_pos)
        # draw enemy missiles
        self.enemy_missile_manager.draw()

That is it, now we do not need to create a brand new enemy ship whenever we need one because we can use the old one from the object pool!

Create Enemy Missile and Enemy Missile Manager

In this article we will create two new classes, enemy missile class and the enemy missile manager class. The enemy missile manager class will be called during each game loop by the enemy manager class to create new enemy missile as well as to update the position of those missiles and draw them on the game scene.

First of all, we will create the enemy missile class which will be used by the enemy missile manager class to create the enemy missile object.

This enemy missile class looks simple and it indeed is simple.

from pygame import math as mt

class Enemymissile(object):

    def __init__(self, missile_surface, x, y):
        self.on = True
        self.missile_surface = missile_surface
        self.x = x
        self.y = y
        self.height = 20
        self.width = 20
        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 only method which is matter in the above class is the update method which will be used to update the position of that enemy missile in every game loop.

The next class is the enemy missile manager class which will be used to create and to control the enemy missiles.

from GameSprite import GameSprite
from pygame.locals import *
from Enemymissile import Enemymissile

class EnemyMissileManager(object):
    
    def __init__(self, scene, player):

        self.scene = scene
        self.player = player
        self.missile_count = 60
        self.missile_list = []
        self.image = 'Asset/e_missile.png'
        self.width = 20
        self.height = 20
        self.rect = Rect(0, 0, self.width, self.height)

        # initialize game sprite object
        self.sprite = GameSprite(self.image, self.rect)

    def create_missile(self, x, y):

        if(self.missile_count >= 0):
            self.missile_surface = self.sprite.getImage()
            self.missile_list.append(Enemymissile(self.missile_surface, x, y))
            self.missile_count -= 1

    def update(self):

        self.missile_update()
        self.check_boundary()

    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 check_boundary(self):

        for i in range(len(self.missile_list)):
            if (self.missile_list[i].y + self.missile_list[i].height > 660):
                self.missile_list[i].on = False

    def draw(self):

        # blit the missile on  the scene
        for i in range(len(self.missile_list)):
            self.scene.blit(self.missile_list[i].missile_surface, self.missile_list[i].missile_pos)

The enemy missile manager class above has below methods:

1) create missile method will create more enemy missile and will be called by the enemy manager class.
2) the update method will call the missile update and the check missile boundary method that will update the position of those missiles and remove those missiles after they have crossed the game scene boundary.
3) the draw method will draw those missiles on the game scene.

Now after we have created those two new classes, we will need to modify the enemy manager class which we have created previously.

from Enemy import Enemy
from GameSprite import GameSprite
from pygame.locals import *
from EnemyMissileManager import EnemyMissileManager
import random

class EnemyManager(object):

    def __init__(self, scene, player):

        self.enemy_missile_manager = EnemyMissileManager(scene, player)
        self.scene = scene
        self.player = player
        self.enemy_count = 10
        self.enemy_list = []
        self.image = 'Asset/enemy0.png'
        self.width = 30
        self.height = 30
        self.rect = Rect(0, 0, self.width, self.height)
        self.more_enemy = 0
        self.y = -50
        self.boundary_width = 660
        self.boundary_height = 660

        # initialize game sprite object
        self.sprite = GameSprite(self.image, self.rect)

    def create_enemy(self, x, y):
        if(self.enemy_count > 0):
            self.enemy_surface = self.sprite.getImage()
            self.enemy_list.append(Enemy(self.enemy_surface, x, y))
            self.enemy_count -= 1

    def update(self):
        if (self.more_enemy > 600):
            self.more_enemy = 0
            x = random.randint(30, self.boundary_width - 50)
            self.create_enemy(x , self.y)  # create more enemy
        else:
            self.more_enemy += 1 # increase time

        self.enemy_update()
        self.check_boundary()
        self.create_enemy_missile()
        self.enemy_missile_manager.update()

    def create_enemy_missile(self):
        for item in list(self.enemy_list):
            if(item.missile_count > 0):
                if(self.player.pos.y - item.y  < 100 and abs(self.player.pos.x - item.x) < 60 ):
                    self.enemy_missile_manager.create_missile(item.x + 5, item.y + 4)
                    item.missile_count -= 1

    def enemy_update(self):

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

    def check_boundary(self):
        for i in range(len(self.enemy_list)):
            if (self.enemy_list[i].y > self.boundary_height):
                self.enemy_list[i].on = False

    def draw(self):

        # blit the enemy on  the scene
        for i in range(len(self.enemy_list)):
            self.scene.blit(self.enemy_list[i].enemy_surface, self.enemy_list[i].enemy_pos)
        # draw enemy missiles
        self.enemy_missile_manager.draw()

The create enemy missile method under the update method will create new enemy missiles during the each game loop update and the missile will only get created when the enemy ship is getting close enough to the player ship because there is no point to fire the missile if the distance between the player ship and the enemy ship is so far apart. We also will need to check for the total missiles an enemy ship can launch before this method can create a new missile from that particular enemy ship. We might want to assign each enemy with it’s own enemy missile manager object so we can better control the missile launching time later on but for now we will create only one enemy missile manager object which will be used by the enemy manager object to create new enemy missiles. The update method of the enemy manager also will call the update method of the enemy missile manager which we have already gone through previously.

Finally the enemy manager draw method will call the enemy missile manager’s draw method to draw those missiles on the game scene during each game loop.

As you can see no contact has been detected yet in this game, we will create the contact manager in our up and coming articles to find out whether the player has hit the enemy ship, the enemy ship has been hit by the player missile and the player has been hit by the enemy missile or not!

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.

Pygame’s Color class demo

Today I have paid a visit to the Pygame document page to revise all the pygame classes one by one because I have already forgotten all of them. In order to create a game with Pygame I will need to get familiar with these classes again. In this article I will write a simple python class which extends the pygame.Color class to demonstrate the use of the pygame Color class. Since most of the time our game will deal with graphic instead of color we do not actually need this class that much but it is good to go through it so we will get familiar with it if we really need to use it later on.

As usual, I open up the PyCharm which is the official ide for my pygame development project to continue with the previously created game project. I am not going to repeat the PyCharm feature which I have already mentioned in my previous article so if you do miss out my previous article then you can read the first chapter of this pygame development project here (Setting up PyCharm for Pygame development in Windows 10 OS). I also assume you are familiar with python because before you can create a game with pygame you will need to have a very strong python programming background.

Now lets create the extension of the Color class, we will create a new python file, make sure you are clicking on the project folder then goto File->New->Python File and give it any name you wish to.

This will be the class which will extend the Pygame Color class, the good thing we create an extension of the Color class is that we can now add in more custom made functions into this class later on if we need it.

Here is our new AirStrikeColor class.

from pygame import Color

class AirStrikeColor(Color):

    def __init__(self, r=255, g= 255, b= 255, a=255):
        Color.__init__(self, r, g, b ,a)

As you can see we have created a default value for all four elements (red, green, blue and alpha) so if the programmer does not enter any value when creating the AirStrikeColor class then this new object will use the default values instead.

Alright, that is about it, we will visit this class again to add in more functions if we need it but for now we can use all the functions of the pygame.Color class in our project as usual.

Next step is to import this new class into the main python file I have created previously. We will now go back to the main python file and import the new class.

from AirStrikeColor import AirStrikeColor #from AirStrikeColor.py import AirStrikeColor class

Also we need to take out the

from pygame import Color

statement because we do not need the main Color class anymore.

Now as usual we will replace the Color class statement with AirStrikeColor class statement like this.

screen.fill(AirStrikeColor())

Run the program again and it works!

Pygame window
Pygame window

Now replace the statement above with own values.

screen.fill(AirStrikeColor(120, 150, 130, 255).correct_gamma(0.5))

New window
New window

If you don’t know where is the main python file please refer back to my previous article.

With that we have concluded this second chapter of our pygame development journal and will now getting ready for the third one.