Create a pool object for player missile

In this article we will create a pool object inside the player missile manager class which will then be used to recycle those player missile objects. Creating pool object for the player missile is a lot more complicated than creating pool object for the enemy missile because in order to use the player missile pool object we will need to amend a few classes such as the game manager class in the pygame project.

Before we create a player missile pool object we will need to do this first,

1) Put the player missile manager directly under the player object so that player object can control the player missile manager which will then control the player missiles.

Here is the edit version of the player class.

from pygame.locals import *
from GameSprite import GameSprite
from pygame import math as mt
from MissileManager import MissileManager
import pygame

class Player(object):

    def __init__(self, scene):

        self.image = 'Asset/player.png'
        self.scene = scene
        self.width = 40
        self.height = 40
        self.missile_count = 10
        self.direction_x = 0
        self.direction_y = 0
        self.rect = Rect(0, 0, self.width, self.height)
        self.sprite = GameSprite(self.image, self.rect)
        self.sprite_surface = self.sprite.getImage()  # get the player sprite surface
        self.bwidth, self.bheight = 660, 660
        self.pos = mt.Vector2(self.bwidth / 2, self.bheight / 2)  # initialize the position of the player sprite
        self.draw_pos = mt.Vector2(self.pos.x, self.pos.y)
        self.missile_manager = MissileManager(scene)

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

    def setX(self, _x):

        # set new x position and detect the boundary on the game scene
        self.direction_x = _x

    def setY(self, _y):

        # set new y position and detect the boundary on the game scene
        self.direction_y = _y

    def setStrike(self, strike):

        self.missile_manager.setStrike(strike)

    def update(self):

        if(self.direction_x == -0.1):
            if(self.pos.x > 0):
                self.pos.x += self.direction_x
        elif(self.direction_x == 0.1):
            if(self.pos.x + self.width <= self.bwidth):
                self.pos.x += self.direction_x
        if(self.direction_y == -0.1):
            if (self.pos.y > 0):
                self.pos.y += self.direction_y
        elif (self.direction_y == 0.1):
            if (self.pos.y + self.height <= self.bheight):
                self.pos.y += self.direction_y

        self.draw_pos = mt.Vector2(self.pos.x, self.pos.y)
        self.missile_manager.update(self.pos.x, self.pos.y)

    def get(self):
        return (self.pos.x, self.pos.y)


    def draw(self):
        self.scene.blit(self.sprite_surface,  self.draw_pos)
        self.missile_manager.draw()

    def getMissileManager(self):

        return self.missile_manager

Next we will need to edit the player missile manager class which will now include a new pool object to recycle the missile.

from Missile import Missile
from GameSprite import GameSprite
from pygame.locals import *
from Objectpool import Objectpool

class MissileManager(object):

    def __init__(self, scene):
        self.scene = scene
        self.missile_count = 10
        self.missile_list = []
        self.image = 'Asset/missile.png'
        self.width = 20
        self.height = 20
        self.rect = Rect(0, 0, self.width, self.height)
        self.strike = False
        self.strike_again = 0
        self.missile_object_pool = Objectpool(self.missile_count)
        # initialize game sprite object
        self.sprite = GameSprite(self.image, self.rect)

    def setStrike(self, strike):

        # set the missile strike flag
        self.strike = strike
        self.strike_again += 1

    def create_missile(self, x, y):
        if(self.missile_count >= 0):

            if (self.missile_object_pool.getSize() > 0):
                self.missile_list.append(self.missile_object_pool.obtain_missile(x, y))
            else:
                self.missile_surface = self.sprite.getImage()
                self.missile_list.append(Missile(self.missile_surface, x, y))
            self.missile_count -= 1

    def update(self,x,y):
        if (self.strike == True and self.strike_again > 1):
            self.strike_again = 0
            self.create_missile(x + 5, y - 8)  # create more missile
        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
                self.missile_object_pool.recycle(item)
            else:
                item.update()

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

Finally we will edit the Game Manager class so it will directly call the player object to update as well as to set the strike’s Boolean variable to the True or False condition.

from Player import Player
from Background import Background
from MissileManager import MissileManager
from EnemyManager import EnemyManager
from Overlap import Overlap
import pygame

class GameManager(object):

    def __init__(self, scene):

        self.scene = scene
        self.player = Player(self.scene)
        self.background = Background(self.scene)
        self.enemy_manager = EnemyManager(self.scene, self.player)
        self.overlap_manager = Overlap()
        self.load_music()
        self.play_music()

    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):
        self.player.setX(_x)

    def set_player_y(self, _y):
        self.player.setY(_y)

    def set_missile_strike(self, strike):
        self.player.setStrike(strike)

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

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

    def draw(self):
        self.background.draw()
        self.player.draw()
        self.enemy_manager.draw()
        pygame.display.flip()

OK, with that we are now ready to create the exploration manager which will be used to create explosion on the game scene in the next chapter.

Create the pool object for Enemy Missile class

In this article we will continue to create a new missile pool object which will be used to recycle the enemy missile object just like the pool object which will be used to recycle the enemy ship object in the previous article. Basically we will use back the previous object pool class which we have created earlier and then add in a new obtain missile method which takes in the x and y coordinate of the enemy ship at that moment that we can later use as the starting point for the missile object returns from the pool. Here is the 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 obtain_missile(self, x, y): # get the missile object from the pool

        if (self.count > 0):
            self.count -= 1
            self.item = self.elist[self.count]
            self.elist[self.count] = None
            self.item.x = x
            self.item.y = y
            self.item.on = True
            return self.item

    def getSize(self):

        return self.count

That is it, now lets amend the Enemy Missile Manager class by adding in the create missile from pool method which will be used to obtain the old missile object from the object pool.

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 create_missile_from_pool(self, x, y, pool):

        if (self.missile_count >= 0):
            self.missile_list.append(pool.obtain_missile(x, y))
            self.missile_count -= 1

    def update(self, pool):

        self.missile_update(pool)
        self.check_boundary()

    def missile_update(self, pool):

        for item in list(self.missile_list):
            if(item.on == False):
                self.missile_list.remove(item)
                self.missile_count += 1
                pool.recycle(item)
            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)

We now need to do the last step which is to edit 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.missile_count = 60
        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)
        self.missile_object_pool = Objectpool(self.missile_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): # get the ship from object pool if the pool is not empty
                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(self.missile_object_pool)

    def create_enemy_missile(self):

        for item in list(self.enemy_list):

            if(self.player.pos.y - item.y  < 100 and abs(self.player.pos.x - item.x) < 60 ):

                if (item.missile_count > 0):

                    if (self.missile_object_pool.getSize() > 0):
                        self.enemy_missile_manager.create_missile_from_pool(item.x + 5, item.y + 4, self.missile_object_pool)

                    else:
                        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! With that we will be able to reuse the old enemy missile object instead of creating a new one. The next article will still be dealing with the pool object and this time we will create an object pool for the player missile object!

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 the Overlap class for Pygame project

Hello there, sorry for a little bit late today because I am busy setting up my old website which is now ready for me to add in more articles into it, if you are interested in more programming articles then do visit this site because I am going to create a brand new laptop application project with python and if you are a python lover then go ahead and bookmark this site and visit it starting from tomorrow!. Gaming Directional, which is the site we both are in now will only concentrate on writing game code so if you want to read other programming articles besides the game one then do visit the above mentioned site instead. OK so much for that lets look at another of the new class I have created for the previous pygame project, which is the Overlap class.

We will call the Overlap class object on every game loop to determine the following:-

1) Does the player ship gets hit by the enemy missile? If so then we will remove that enemy missile.
2) Does the player ship hits one of the enemy ship? If so then we will remove that enemy ship.
3) Does the enemy ship gets hit by a player missile? If so then remove both of them.

We will not going to do anything on the player ship yet even if it gets hit by the enemy ship or missile because we will deal with this issue later on.

Here is the entire Overlap class.

from pygame.locals import *

class Overlap(object):

    def __init__(self):
        pass # nothing here

    # is player and enemy, player missile, enemy missile overlap
    def iseOverlap(self, player, em, pm):

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

        for i in range(len(em.enemy_list)): # is player collides with enemy

            self.em_rect = Rect(em.enemy_list[i].x, em.enemy_list[i].y, em.width, em.height)
            if (self.player_rect.colliderect(self.em_rect)):
                em.enemy_list[i].on = False

        for i in range(len(em.enemy_missile_manager.missile_list)): # is enemy missile hits player

            self.em_rect = Rect(em.enemy_missile_manager.missile_list[i].x, em.enemy_missile_manager.missile_list[i].y, em.enemy_missile_manager.width, em.enemy_missile_manager.height)
            if (self.player_rect.colliderect(self.em_rect)):
                em.enemy_missile_manager.missile_list[i].on = False

        for i in range(len(em.enemy_list)): # is player missile hits enemy

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

            for j in range(len(pm.missile_list)):

                self.pm_rect = Rect(pm.missile_list[j].x, pm.missile_list[j].y, pm.width, pm.height)

                if (self.em_rect.colliderect(self.pm_rect)):
                    em.enemy_list[i].on = False
                    pm.missile_list[j].on = False

We also need to edit the Game Manager class like this.

from Player import Player
from Background import Background
from MissileManager import MissileManager
from EnemyManager import EnemyManager
from Overlap import Overlap
import pygame

class GameManager(object):

    def __init__(self, scene):

        self.scene = scene
        self.player = Player(self.scene)
        self.background = Background(self.scene)
        self.missile_manager = MissileManager(self.scene, self.player)
        self.enemy_manager = EnemyManager(self.scene, self.player)
        self.overlap_manager = Overlap()
        self.load_music()
        self.play_music()

    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):
        self.player.setX(_x)

    def set_player_y(self, _y):
        self.player.setY(_y)

    def set_missile_strike(self, strike):
        self. missile_manager.setStrike(True)

    def update(self):
        self.player.update()
        self.missile_manager.update()
        self.enemy_manager.update()
        self.isOverlap()

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

    def draw(self):
        self.background.draw()
        self.player.draw()
        self.missile_manager.draw()
        self.enemy_manager.draw()
        pygame.display.flip()

And here is the outcome

Alright then, after this class we will continue to create the recycle class tomorrow which we will use to recycle and then reuse back the game object so we do not need to create a new one which will increase the burden of the computer’s processor.

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 Enemy Manager Class and Enemy Class in a Pygame Project

Hello again, today chapter will be very short but rich in content. As I have mentioned earlier, we have finished the stage one of the game creation process yesterday and today we have entered the stage two of our game creation process, which is to create the enemy, enemy missile, level and the exploration classes, we certainly are getting very close now to finish up this latest pygame project.

In this short article you will read all the code for the Enemy Manager and Enemy Class plus I do have a special surprise for you at the end of this article so make sure you read it till the end.

This is the part one of the three part enemy’s class related article series and in this part we will create enemy spaceships that will come down from a certain distance above the game scene, the enemy object which get passed the bottom of the game scene will get removed by the Enemy Manager which will then create a new enemy object after it has removed the old one. We will generate the enemy object from a random x position within this game scene with it’s y position start off from a fix distance above the top of the game scene. Besides that, we have also included the time control variable in the Enemy Manager class so this class will generate the enemy at an acceptable speed. The contact detection between enemy and player object, recycle of the enemy object, enemy missile object and many more methods and classes will be created in the upcoming articles.

Below is the enemy class with an update method which will move the enemy to a new y position in every game loop.

from pygame import math as mt

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.enemy_pos = mt.Vector2(self.x, self.y)

    def update(self):
        self.y += 0.1
        self.enemy_pos = mt.Vector2(self.x, self.y)

Here is the enemy manager class which is used to control the enemy with the features I have mentioned above.

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

class EnemyManager(object):

    def __init__(self, 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()

    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)

After we have created these two classes it is time to modify the Game Manager class which will call the Enemy Manager Class to create more enemy as well as updates the position of those enemies on the game scene plus draws the enemy object on the scene.

from Player import Player
from Background import Background
from MissileManager import MissileManager
from EnemyManager import EnemyManager
import pygame

class GameManager(object):

    def __init__(self, scene):

        self.scene = scene
        self.player = Player(self.scene)
        self.background = Background(self.scene)
        self.missile_manager = MissileManager(self.scene, self.player)
        self.enemy_manager = EnemyManager(self.scene, self.player)
        self.load_music()
        self.play_music()

    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):
        self.player.setX(_x)

    def set_player_y(self, _y):
        self.player.setY(_y)

    def set_missile_strike(self, strike):
       self. missile_manager.setStrike(True)

    def update(self):
        self.player.update()
        self.missile_manager.update()
        self.enemy_manager.update()

    def draw(self):
        self.background.draw()
        self.player.draw()
        self.missile_manager.draw()
        self.enemy_manager.draw()
        pygame.display.flip()

Now run the main pygame program again and you will get the below outcome. As you can see the enemy ship will just get through the player ship with no contact with that player ship as well as no missile shooting which we will deal with in the next articles.

HERE IS THE BONUS:

Below is the game music which I am going to use in this new pygame project, besides a game developer I am also a soundtrack creator, you can subscribe and listen to those new musics on my soundcloud channel.

Game Manager Class and the modify version of the main pygame file

Finally I have finished linking everything together and get ready for the next stage. Here is the Game Manager class which is the only class we need in the main pygame project file. This class contains everything we need to control game objects, play background music and render the game graphics on the game scene.

from Player import Player
from Background import Background
from MissileManager import MissileManager
import pygame

class GameManager(object):

    def __init__(self, scene):

        self.scene = scene
        self.player = Player(self.scene)
        self.background = Background(self.scene)
        self.missile_manager = MissileManager(self.scene, self.player)
        self.load_music()
        self.play_music()

    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):
        self.player.setX(_x)

    def set_player_y(self, _y):
        self.player.setY(_y)

    def set_missile_strike(self, strike):
       self. missile_manager.setStrike(True)

    def update(self):
        self.player.update()
        self.missile_manager.update()

    def draw(self):
        self.background.draw()
        self.player.draw()
        self.missile_manager.draw()
        pygame.display.flip()

No new method has been introduced in this class, what we do is just to group the unorganized code in the previous main pygame file to a single Game Manager class. The main python file now looks really neat because all we need is just a single Game Manager class to control everything. Here is the modify version of the main pygame file.

import sys, 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)

while True:

    for event in pygame.event.get():

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

        # detect key press event 
        if event.type == KEYDOWN:

            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)

        elif event.type == KEYUP:
            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)

    game_manager.update()
    game_manager.draw()

In the next few chapters we will create the enemy ship class as well as the explosion class and the game level class which will be used to control the level of the game.

The modify version of the Pygame Missile Manager Class

Before we go ahead and create the Game Manager class we will need to take out all the code which are related to the missile manager in the main python file as shown in the previous article and put them all under a single missile manager class. Here is the modify version of the missile manager class as compared with the previous version.. This class will take in both the scene as well as the player object to start with.

from Missile import Missile
from GameSprite import GameSprite
from pygame.locals import *

class MissileManager(object):

    def __init__(self, scene, player):
        self.scene = scene
        self.player = player
        self.missile_count = 10
        self.missile_list = []
        self.image = 'Asset/missile.png'
        self.width = 20
        self.height = 20
        self.rect = Rect(0, 0, self.width, self.height)
        self.strike = False
        self.strike_again = 0
        # initialize game sprite object
        self.sprite = GameSprite(self.image, self.rect)

    def setStrike(self, strike):

        # set the missile strike flag
        self.strike = strike
        self.strike_again += 1

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

    def update(self):
        if (self.strike == True and self.strike_again > 1):
            self.strike_again = 0
            x, y = self.player.get()
            self.create_missile(x + 5, y - 8)  # create more missile
        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 < 0):
                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)

As you can see we will use a single update method to control both the missile update and the check boundary method. We have also included a new draw method to draw the missiles on the game scene. The missile manager class does not need to return the missile list anymore to the main file so the previous method has been totally removed. Finally we have a set strike method to turn the strike flag on or off depends on whether the space key has been pressed or released.

That is it for this one, now lets us look at the Game Manager class in the next chapter.

Create a background object class in Pygame

In this article we will create the next pygame object class, which is the background object class that will render the background graphic on the game scene, just like the player class in the previous article, background class will take in a scene reference object which will be used by this background class to blit the background graphic on the game scene. It has a very simple draw method which will be called in each game loop to redraw the background game graphic. Here is the entire class.

from BgSprite import BgSprite
from pygame.locals import *
from pygame import math as mt

class Background(object):

    def __init__(self, scene):
        self.scene = scene
        self.image = 'Asset/bg.png'
        self.rect = Rect(0, 0, 660, 660)
        self.sprite = BgSprite(self.image, self.rect)
        self.surface = self.sprite.getImage()  # get the background sprite surface
        self.draw_pos = mt.Vector2(0, 0)

    def draw(self):
        self.scene.blit( self.surface, self.draw_pos) # draw a background sprite

That is it, as simple as it is! Now before we can create our Game Manager class we will need to modify the Missile Manager class we have created previously in the next chapter so it can be called directly by our new Game Manager class later on.

Create a Player object in Pygame

Hello, sorry for not posting any article yesterday because I am very busy with my offline business but today I have a whole day to write more articles and I am going to create three articles for today. First of all, do you people still remember I have mentioned that I will create one single Game Manager to manage all the game objects on the game scene in my previous article? Yes we are going to do that soon, but before we doing that we will need to first create a new class for each game objects on the game scene. In this article we will start to turn our first game object into a class by it’s own, we will create a class for the Player object.

This player object will receive the scene object from the main pygame file which it can then use to blit the player graphic on the scene, besides that it can also receive the key down event and the key up event so it can move the player object to a new location on the game scene with it’s update position method.

Below is the entire Player class, more methods will be added in the future but for now here is it.

from pygame.locals import *
from GameSprite import GameSprite
from pygame import math as mt
import pygame

class Player(object):

    def __init__(self, scene):
        self.image = 'Asset/player.png'
        self.scene = scene
        self.width = 40
        self.height = 40
        self.direction_x = 0
        self.direction_y = 0
        self.rect = Rect(0, 0, self.width, self.height)
        self.sprite = GameSprite(self.image, self.rect)
        self.sprite_surface = self.sprite.getImage()  # get the player sprite surface
        self.bwidth, self.bheight = 660, 660
        self.pos = mt.Vector2(self.bwidth / 2, self.bheight / 2)  # initialize the position of the player sprite
        self.draw_pos = mt.Vector2(self.pos.x, self.pos.y)

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

    def setX(self, _x):

        # set new x position and detect the boundary on the game scene
        self.direction_x = _x

    def setY(self, _y):

        # set new y position and detect the boundary on the game scene
        self.direction_y = _y

    def update(self):

        if(self.direction_x == -0.1):
            if(self.pos.x > 0):
                self.pos.x += self.direction_x
        elif(self.direction_x == 0.1):
            if(self.pos.x + self.width <= self.bwidth):
                self.pos.x += self.direction_x
        if(self.direction_y == -0.1):
            if (self.pos.y > 0):
                self.pos.y += self.direction_y
        elif (self.direction_y == 0.1):
            if (self.pos.y + self.height <= self.bheight):
                self.pos.y += self.direction_y

        self.draw_pos = mt.Vector2(self.pos.x, self.pos.y)

    def get(self):
        return (self.pos.x, self.pos.y)


    def draw(self):
        self.scene.blit(self.sprite_surface,  self.draw_pos)

As you can see, it also has an extra get method which will return the new x and y position of the player object to be used by the missile manager to position the new missile. That is it, we will now move on to create the background object class in the next article.