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.

Increase the points that need to win the game

What is up buddy? In this article, we will continue to edit our pygame project by increasing the difficulty to win this game. 1) We will increase the points that we need to win the game by double. 2) We will also increase the damage points to 3 instead of 1 when the player gets hit by the missile from the horizontal moving enemy ship. We only need to update one file to make those changes, the overlap class.

We will come back and do more editions on this file later on but for now, let us edit the above-mentioned items first.

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)
                    if(level == 3):
                        score.set_score(-3)
                    else:
                        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)):

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

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

The changes above will not be shown in the latest version of this game immediately because I will only update this project once a week. By the way, have you downloaded this game already, if not then you can do so from the below widgets.

Download Air Strike

Tomorrow I will start to write about the next project as well as continue with the present project, 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

Change the direction of the enemy ship

Hello and happy new year to all readers of this website, in this new year’s eve I would like to list out the entire plan for this website in the year 2019 before we proceed even further. After a long thought about the future plan for this website in the year 2019 I have decided to continue writing about the previous pygame project which I have developed last year which means instead of stop posting about any further change or the latest features that have been included into this project I will continue to post an update on this project so you can play the game and continue to learn about the programming part of this game at the same time. If you have not yet downloaded version 1 of this game then go ahead and do so first through below link. The latest update of this game on this article will not appear immediately on those major gaming sites, this game will only get updated once a week on those major gaming sites.

Besides continue developing and posting the previous project, I will also start to write about the next pygame project which is a maze game project in this same website, so make sure you subscribed to this website by clicking on the bell button below this post.

Alright, so much for that, now let us continue with the previous pygame project which we will now change the direction of the enemy ship from which previously moves horizontally from left to right to move in both directions instead. In the previous program, a new enemy ship which moves from left to right will be created each time the player has destroyed the old one which makes the path of that enemy ship always look the same. In this new update, we will change the direction of the new enemy ship from right to left if the old one which gets destroyed is moving from left to right and vice-versa. In order to achieve this, we only need to edit the enemy manager class like before.

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

class EnemyManager(object):

    def __init__(self, scene, player, game_level):

        self.enemy_missile_manager = EnemyMissileManager()
        self.scene = scene
        self.player = player
        self.enemy_count = 10
        self.horizontal_enemy_count = 1
        self.missile_count = 60
        self.enemy_list = []
        self.horizontal_enemy_list = []
        self.image = 'Asset/enemy0.png'
        self.image1 =  'Asset/enemy1.png'
        self.image2 = 'Asset/enemy2.png'
        self.width = 30
        self.height = 30
        self.width1 = 130
        self.height1 = 130
        self.rect = Rect(0, 0, self.width, self.height)
        self.rect1 = Rect(0, 0, self.width1, self.height1)
        self.more_enemy = 0
        self.y = -50
        self.boundary_width = 660
        self.boundary_height = 660
        self.object_pool = Objectpool(self.enemy_count)
        self.horizontal_object_pool = Objectpool(self.horizontal_enemy_count)
        self.next_enemy = 0
        self.level = game_level

        # initialize game sprite object
        self.sprite = GameSprite(self.image, self.rect)
        self.sprite1 = GameSprite(self.image1, self.rect)
        self.sprite2 = GameSprite(self.image2, self.rect1)

    def create_enemy(self, x, y):

        if(self.enemy_count &gt; 0):

            if(self.object_pool.getSize() &gt; 0): # get the ship from object pool if the pool is not empty
                self.enemy_list.append(self.object_pool.obtain())
            else: # objects setup based on the level of the game
                if(self.level == 1):
                    self.enemy_surface = self.sprite.getImage()
                elif(self.level == 2 or self.level == 3):
                    if(self.next_enemy == 0):
                        self.enemy_surface = self.sprite.getImage()
                        self.next_enemy += 1
                    elif(self.next_enemy == 1):
                        self.enemy_surface = self.sprite1.getImage()
                        self.next_enemy = 0
                self.enemy_list.append(Enemy(self.enemy_surface, x, y))
            self.enemy_count -= 1

    def create_horizontal_enemy(self, x, y):

        if (self.horizontal_enemy_count &gt; 0):

            if (self.horizontal_object_pool.getSize() &gt; 0):  # get the ship from object pool if the pool is not empty
                self.horizontal_enemy_list.append(self.horizontal_object_pool.obtain())
            else:  # objects setup based on the level of the game
                if (self.level == 3):
                    self.enemy_surface1 = self.sprite2.getImage()
                self.horizontal_enemy_list.append(Enemy1(self.enemy_surface1, x, y))
            self.horizontal_enemy_count -= 1


    def update(self):

        if (self.level == 1 or self.level == 2):

            if (self.more_enemy &gt; 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

        elif(self.level == 3):

            if (self.more_enemy &gt; 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

            if(self.horizontal_enemy_count &gt; 0):
                self.create_horizontal_enemy(-130, 200)  # create new enemy

        self.create_enemy_missile()
        self.enemy_update()
        self.check_boundary()

    def create_enemy_missile(self):

        for item in list(self.enemy_list):

            if(self.player.pos.y - item.y  &lt; 200 and abs(self.player.pos.x - item.x) &lt; 160):

                item.create_enemy_missile(self.enemy_missile_manager)

        if(self.level == 3):

            for item in list(self.horizontal_enemy_list):
                item.create_enemy_missile(self.enemy_missile_manager)

    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:
                if ((self.player.pos.y - item.y &lt; 200 and self.player.pos.y - item.y &gt; -2) and abs(self.player.pos.x - item.x) &lt; 200):
                    item.update((self.player.pos.x - item.x) * 0.004, 0.1)
                else:
                    item.update(0, 0.1)

        if (self.level == 3):

            for item in list(self.horizontal_enemy_list):

                if (item.on == False):

                    self.horizontal_enemy_count += 1
                    item.y = 220

                    if(item.direction == True):
                        item.x = 800
                        item.direction = False
                    else:
                        item.x = -130
                        item.direction = True
                    self.horizontal_enemy_list.remove(item)
                    item.on = True
                    self.horizontal_object_pool.recycle(item)

                else:
                    item.update()

    # check the boundary of the enemy ship with the game scene area
    def check_boundary(self):

        for i in range(len(self.enemy_list)):
            if (self.enemy_list[i].y &gt; self.boundary_height):
                self.enemy_list[i].on = False

        if (self.level == 3):
            for i in range(len(self.horizontal_enemy_list)):
                if (self.horizontal_enemy_list[i].x &gt; self.boundary_width):
                    self.horizontal_enemy_list[i].direction = False
                elif(self.horizontal_enemy_list[i].x &lt;= -130):
                    self.horizontal_enemy_list[i].direction = True

    def draw(self):

        # blit the enemy and enemy missiles 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)
            self.enemy_list[i].missile_draw(self.scene)

        if(self.level == 3):
            for i in range(len(self.horizontal_enemy_list)):
                self.scene.blit(self.horizontal_enemy_list[i].enemy_surface, self.horizontal_enemy_list[i].enemy_pos)
                self.horizontal_enemy_list[i].missile_draw(self.scene)

By changing the above program we will be able to achieve that change of path effect for the horizontally moving enemy ship.

Change the direction of the enemy ship

I wish you all the best of luck in the year 2019 and stay tuned for more game development articles in this website.

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.

Touch up the game level scene

Hi, it has been a few days I am not posting anything because I am busy preparing a few projects at the same time. Today I have finally finished tidily up this pygame project and it will be ready to ship to major game sites where you can then download this demo game and take a look at it after reading all those game project source codes in this website. The final piece of code which I am going to post it here is the game level scene code where I have changed the number associates with each level from top to bottom instead of from bottom to top as you have seen previously. In order to achieve that we need to edit the start scene class again.

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):

        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.over_image = 'Asset/ove.png'
        self.next_image = 'Asset/next.png'
        self.win_image = 'Asset/winn.png'
        self.general_image = 'Asset/general.png'
        self.about_page = 'Asset/about_page.png'
        self.manual_page = 'Asset/manual_page.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, 29, 30)
        self.game_logo_rect = Rect(0, 0, 160, 160)

        self.sprite = BgSprite(self.general_image, self.bg_rect)
        self.sprite_about = BgSprite(self.about_page, self.bg_rect)
        self.sprite_manual = BgSprite(self.manual_page, self.bg_rect)
        self.sprite_win = BgSprite(self.win_image, self.bg_rect)
        self.sprite_over = BgSprite(self.over_image, self.bg_rect)
        self.sprite_next = BgSprite(self.next_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.about_surface = self.sprite_about.getImage()  # get the about sprite surface
        self.manual_surface = self.sprite_manual.getImage()  # get the manual sprite surface
        self.win_surface = self.sprite_win.getImage()  # get the win sprite surface
        self.next_surface = self.sprite_next.getImage()  # get the next level sprite surface
        self.over_surface = self.sprite_over.getImage()  # get the game over 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.font = txt.Font(None, 90)
        self.credit_font = txt.Font(None, 50)
        self.score_text = "Top Achievements"
        self.credit_text = "Create by : IslandTropicalMan"
        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)
        self.x_title = 330 - self.text_width/2
        self.x_credit = 330 - self.credit_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.credit_text = self.credit_font.render(self.credit_text, 1, (255, 255, 255))
        self.score_value_text = ''
        self.f1 = None
        self.font1 = txt.Font(None, 100)
        self.score_rect = Rect(100, self.y_title+self.text_height, 100, 100)

        self.home_background_color = AirStrikeColor(0, 0, 0, 255)

    def recal_level(self): # get the top 5 levels
        self.count = 0
        self.origin = 0
        try:
            f = open("level.txt", "r")

            try:
                if f.mode == 'r':
                    self.f1 = f.readlines()
                    for x in self.f1:
                        self.count += 1
            finally:
                f.close()

        except IOError:
            print('Error')

    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.blit(self.over_surface, self.draw_pos)  # draw a game over sprite

        elif (state == 3):
            self.scene.blit(self.next_surface, self.draw_pos)  # draw a next level sprite

        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.blit(self.pause_surface,  self.draw_pos)  # draw a score sprite
            self.scene.fill(self.home_background_color)  # draw a background
            self.scene.blit(self.title_score_text, self.title_rect) # the score title first

            while(self.count > 0):
                self.count -= 1
                self.origin += 1
                self.score_rect = Rect(130, self.y_title + self.text_height + self.origin * 80, 100, 100)
                self.score_value_text = str(self.origin) + ".) Level " + self.f1[self.count][0:1]
                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

            if(self.count <= 0):
                self.count = self.origin
                self.origin = 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()

With that, we have now concluded all the game source code tutorials and we are now ready to move to the next pygame project, so stay tuned. Do visit the game project page for the latest news regarding this pygame project.

Air Strike

Air Strike is a single player shooting game for windows os laptop user. In this game, you will need to shoot down as many enemy ships as possible to advance to the next level. Make sure you are not getting hit by the enemy ship or else it will be game over. Also, do avoid as many enemy missiles as possible. The game will have 10 levels in total and currently it is at level 3, I will continue to create one game level per week after the beta stage of this game has been released on major game sites until this game has finally reached level 10. After that, I will continue to include more features into the game which means although you are playing the same level again and again but each time you will find out that a new game character has been added into that same level after each game’s updates.

Game Instruction: Use the right, left, up and down arrow key on your keyboard to move the ship around. Use the space bar to shoot a missile at the enemy. Press ‘p’ during the game will bring out the pause screen where you can then continue to play the game or go back to the home page. Press ‘s’ on the keyboard will save a copy of the screenshot during the game.

Game Scene

You can download this game through below game sites.

Download Air Strike

This game is still in it’s beta stage which means it is more like a demo game for python program rather than a real game but no worry because more features will be included from now onward! If you find any bug in this game do let me know through the comment box below this main post.

Hope you will enjoy this game and let you friend knows about it!

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!

The beginning of Game AI

We have basically finished including all the game features in our pygame project and we are now ready to further tune up this pygame project. In this article, we will further tune up the path of the enemy ships. In the previous program, the enemy ship is moving downward in the vertical position and shooting missile at the player if the distance between the player and the enemy is close enough. In this article, we will make the enemy a lot smarter than previously by making it moves toward the direction of the player when it spots the player within a certain range.

We will need to modify the enemy class’s update method by including the x and the y parameter into it that will be used to adjust the path of the enemy ship to make it moves toward the player direction during the game.

from pygame import math as mt
from Objectpool import Objectpool

class Enemy(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.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, x, y):
        self.y += y
        self.x += x
        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 &gt; 300):

            self.missile_timer = 0

            if (self.missile_object_pool.getSize() &gt; 0):
                enemy_missile_manager.create_missile(self.x + 5, self.y + 4, self.missile_object_pool, self.missile_list)
            else:
                enemy_missile_manager.create_missile(self.x + 5, self.y + 4, None, self.missile_list)

        else:

            self.missile_timer += 1

The next class we need to modify is the enemy manager class which we will adjust the range where the enemy will fire a missile at the player as well as creating the range where the enemy will start to move toward the player during the game.

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

class EnemyManager(object):

    def __init__(self, scene, player, game_level):

        self.enemy_missile_manager = EnemyMissileManager()
        self.scene = scene
        self.player = player
        self.enemy_count = 10
        self.horizontal_enemy_count = 1
        self.missile_count = 60
        self.enemy_list = []
        self.horizontal_enemy_list = []
        self.image = 'Asset/enemy0.png'
        self.image1 =  'Asset/enemy1.png'
        self.image2 = 'Asset/enemy2.png'
        self.width = 30
        self.height = 30
        self.width1 = 130
        self.height1 = 130
        self.rect = Rect(0, 0, self.width, self.height)
        self.rect1 = Rect(0, 0, self.width1, self.height1)
        self.more_enemy = 0
        self.y = -50
        self.boundary_width = 660
        self.boundary_height = 660
        self.object_pool = Objectpool(self.enemy_count)
        self.horizontal_object_pool = Objectpool(self.horizontal_enemy_count)
        self.next_enemy = 0
        self.level = game_level

        # initialize game sprite object
        self.sprite = GameSprite(self.image, self.rect)
        self.sprite1 = GameSprite(self.image1, self.rect)
        self.sprite2 = GameSprite(self.image2, self.rect1)

    def create_enemy(self, x, y):

        if(self.enemy_count &gt; 0):

            if(self.object_pool.getSize() &gt; 0): # get the ship from object pool if the pool is not empty
                self.enemy_list.append(self.object_pool.obtain())
            else: # objects setup based on the level of the game
                if(self.level == 1):
                    self.enemy_surface = self.sprite.getImage()
                elif(self.level == 2 or self.level == 3):
                    if(self.next_enemy == 0):
                        self.enemy_surface = self.sprite.getImage()
                        self.next_enemy += 1
                    elif(self.next_enemy == 1):
                        self.enemy_surface = self.sprite1.getImage()
                        self.next_enemy = 0
                self.enemy_list.append(Enemy(self.enemy_surface, x, y))
            self.enemy_count -= 1

    def create_horizontal_enemy(self, x, y):

        if (self.horizontal_enemy_count &gt; 0):

            if (self.horizontal_object_pool.getSize() &gt; 0):  # get the ship from object pool if the pool is not empty
                self.horizontal_enemy_list.append(self.horizontal_object_pool.obtain())
            else:  # objects setup based on the level of the game
                if (self.level == 3):
                    self.enemy_surface1 = self.sprite2.getImage()
                self.horizontal_enemy_list.append(Enemy1(self.enemy_surface1, x, y))
            self.horizontal_enemy_count -= 1


    def update(self):

        if (self.level == 1 or self.level == 2):

            if (self.more_enemy &gt; 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

        elif(self.level == 3):

            if (self.more_enemy &gt; 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

            if(self.horizontal_enemy_count &gt; 0):
                self.create_horizontal_enemy(-130, 200)  # create new enemy

        self.create_enemy_missile()
        self.enemy_update()
        self.check_boundary()

    def create_enemy_missile(self):

        for item in list(self.enemy_list):

            if(self.player.pos.y - item.y  &lt; 200 and abs(self.player.pos.x - item.x) &lt; 160):

                item.create_enemy_missile(self.enemy_missile_manager)

        if(self.level == 3):

            for item in list(self.horizontal_enemy_list):
                item.create_enemy_missile(self.enemy_missile_manager)

    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:
                if ((self.player.pos.y - item.y &lt; 200 and self.player.pos.y - item.y &gt; -2) and abs(self.player.pos.x - item.x) &lt; 200):
                    item.update((self.player.pos.x - item.x) * 0.005, 0.1)
                else:
                    item.update(0, 0.1)

        if (self.level == 3):

            for item in list(self.horizontal_enemy_list):
                if (item.on == False):
                    self.horizontal_enemy_list.remove(item)
                    self.horizontal_enemy_count += 1
                    item.y = 220
                    item.x = -130
                    item.on = True
                    self.horizontal_object_pool.recycle(item)
                else:
                    item.update()

    # check the boundary of the enemy ship with the game scene area
    def check_boundary(self):

        for i in range(len(self.enemy_list)):
            if (self.enemy_list[i].y &gt; self.boundary_height):
                self.enemy_list[i].on = False

        if (self.level == 3):
            for i in range(len(self.horizontal_enemy_list)):
                if (self.horizontal_enemy_list[i].x &gt; self.boundary_width):
                    self.horizontal_enemy_list[i].direction = False
                elif(self.horizontal_enemy_list[i].x &lt;= -130):
                    self.horizontal_enemy_list[i].direction = True

    def draw(self):

        # blit the enemy and enemy missiles 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)
            self.enemy_list[i].missile_draw(self.scene)

        if(self.level == 3):
            for i in range(len(self.horizontal_enemy_list)):
                self.scene.blit(self.horizontal_enemy_list[i].enemy_surface, self.horizontal_enemy_list[i].enemy_pos)
                self.horizontal_enemy_list[i].missile_draw(self.scene)

Now, whenever the enemy spots the player within a certain range it will move toward that player.

The enemy will move toward the player