Create a win scene and the level manager class for pygame project

In this article we will create a win scene which will be shown after the player has won the final level of the game, the win scene will then ask the player whether he wants to start that game from the beginning or not? We will also create a framework for the level manager class which we will further add in more features in the next chapter.

First of all, we will modify the start scene class again to include a win scene graphic.

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

class StartScene(object):

    def __init__(self, scene):
        self.scene = scene
        self.button_image = 'Asset/button_play.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.bg_rect = Rect(0, 0, 660, 660)
        self.button_rect = Rect(0, 0,  306, 112)
        self.sprite = BgSprite(self.bg_image, 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_button = GameSprite(self.button_image, self.button_rect)
        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.surface = self.sprite.getImage()  # get the start scene sprite surface
        self.button_surface = self.sprite_button.getImage() # get the button sprite surface
        self.draw_pos = mt.Vector2(0, 0)
        self.draw_button_pos = mt.Vector2(177, 274)

    def draw(self, state):

        if(state == 0):
            self.scene.blit(self.surface, self.draw_pos) # draw a start scene 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

        self.scene.blit(self.button_surface, self.draw_button_pos)  # draw a button sprite
        pygame.display.flip()

Next we will modify the overlap class where we will call the level manager to update the game status instead of directly call the game manager to do the same thing whenever the player has reached a new level.

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.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
                if(em.enemy_list[i].hit == False):
                    ex.create_explosion(player.pos.x + 2, player.pos.y + 2)
                    em.enemy_list[i].hit = True
                    gm.state = gm.OVER
                    gm.setup(gm.level_manager.get_level())

        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
                ex.create_explosion(player.pos.x + 2, player.pos.y + 2)
                score.set_score(-1)
                if(score.score < 0):
                        gm.state = gm.OVER
                        gm.setup(gm.level_manager.get_level())

        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(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)):
                    em.enemy_list[i].on = False
                    player.getMissileManager().missile_list[j].on = False
                    if (em.enemy_list[i].hit == False):
                        ex.create_explosion(em.enemy_list[i].x, em.enemy_list[i].y + 2)
                        em.enemy_list[i].hit = True
                        score.set_score(1)
                        if(score.score >= 30):
                            gm.level_manager.increase_level()

Next We will need to create an instance of the level manager class within the game manager class and check the game level in game manager’s setup method. Besides that we will also create a win state game variable to represent the winning state of the game.

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

class GameManager(object):

    def __init__(self, scene):

        self.scene = scene
        self.start_scene = StartScene(scene)
        self.load_music()
        self.play_music()
        self.overlap_manager = Overlap()
        self.level_manager = LevelManager(self)

        self.setup(0)

        #game state
        self.LOAD = 0
        self.GAME = 1
        self.OVER = 2
        self.NEXT = 3
        self.WIN = 4

        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)

        if(self.game_level == 0):
            self.player = Player(self.scene)
            self.enemy_manager = EnemyManager(self.scene, self.player)
            self.explosion_manager = ExplosionManager(self.scene)

    def loop(self):

        if(self.state == self.LOAD or self.state == self.OVER or self.state == self.NEXT or self.state == self.WIN):

            self.start_scene.draw(self.state)

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

            self.update()
            self.draw()

    def isAreaClick(self, pos):
        if (self.state == self.LOAD or self.state == self.OVER or self.state == self.NEXT or self.state == self.WIN):
            self.rect = Rect(177, 274, 306, 112) # the position of the play button on the scene
            x, y = pos
            if(self.rect.collidepoint(x, y)):
                self.state = self.GAME


    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 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):
        self.background.draw()
        self.player.draw()
        self.enemy_manager.draw()
        self.explosion_manager.draw()
        self.score_manager.draw()
        pygame.display.flip()

As you can see the setup method will check which game level is that and do the game objects setup according to that level. There is only one level at the moment so we will need to further modify the program in the next chapter, for example we will need to modify the enemy manager class because we will need to create different enemies at different level of the game!

Now here is the level manager class.

class LevelManager(object):

    def __init__(self, gm):

        self.game_manager = gm
        self.level = 0

    def increase_level(self):

        self.level += 1
        if(self.level > 1):
            self.game_manager.state = self.game_manager.WIN
            self.level = 0
            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

The class is very simple at the moment, the increase level method either increase the game level or reset the level to 0 if the player has won the game! We can now concentrate on the level manager class in the next chapter and come back again to create a few more scenes like the about scene which contains game instructions as well as the credit scene which gives credit to the game creator. If you like this post don’t forget to click on the red bell button below this post to subscribe to the post’s notification or you also can subscribe to the individual rss feed from the sidebar of this website. There are more articles related to the game creation topic coming out almost everyday so make sure to subscribe to this website to get the latest daily game development article!

Create a next level scene for pygame project

In this article we will create a next level scene which will be displayed whenever the player has gained 30 points. Just like the previous chapter we are going to use back the start scene class as well as modify the game manager class and the overlap class

First of all we will create the next scene surface and draw it on the game scene whenever the state of the game has changed to the next level state.

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

class StartScene(object):

    def __init__(self, scene):
        self.scene = scene
        self.button_image = 'Asset/button_play.png'
        self.bg_image = 'Asset/start.png'
        self.over_image = 'Asset/ove.png'
        self.next_image = 'Asset/next.png'
        self.bg_rect = Rect(0, 0, 660, 660)
        self.button_rect = Rect(0, 0,  306, 112)
        self.sprite = BgSprite(self.bg_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_button = GameSprite(self.button_image, self.button_rect)
        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.surface = self.sprite.getImage()  # get the start scene sprite surface
        self.button_surface = self.sprite_button.getImage() # get the button sprite surface
        self.draw_pos = mt.Vector2(0, 0)
        self.draw_button_pos = mt.Vector2(177, 274)

    def draw(self, state):

        if(state == 0):
            self.scene.blit(self.surface, self.draw_pos) # draw a start scene 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

        self.scene.blit(self.button_surface, self.draw_button_pos)  # draw a button sprite
        pygame.display.flip()

Next we will edit the game manager class by creating the next level game state variable and including it in the relevant methods.

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 *
import pygame

class GameManager(object):

    def __init__(self, scene):

        self.scene = scene
        self.start_scene = StartScene(scene)
        self.load_music()
        self.play_music()
        self.overlap_manager = Overlap()

        self.setup()

        #game state
        self.LOAD = 0
        self.GAME = 1
        self.OVER = 2
        self.NEXT = 3

        self.state = self.LOAD

    def setup(self):

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

    def loop(self):

        if(self.state == self.LOAD or self.state == self.OVER or self.state == self.NEXT):

            self.start_scene.draw(self.state)

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

            self.update()
            self.draw()

    def isAreaClick(self, pos):
        if (self.state == self.LOAD or self.state == self.OVER or self.state == self.NEXT):
            self.rect = Rect(177, 274, 306, 112) # the position of the play button on the scene
            x, y = pos
            if(self.rect.collidepoint(x, y)):
                self.state = self.GAME


    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 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):
        self.background.draw()
        self.player.draw()
        self.enemy_manager.draw()
        self.explosion_manager.draw()
        self.score_manager.draw()
        pygame.display.flip()

The final step is to edit the overlap class where we will change the game state to the next level state if the player has gained 30 points.

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.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
                if(em.enemy_list[i].hit == False):
                    ex.create_explosion(player.pos.x + 2, player.pos.y + 2)
                    em.enemy_list[i].hit = True
                    gm.state = gm.OVER
                    gm.setup()

        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
                ex.create_explosion(player.pos.x + 2, player.pos.y + 2)
                score.set_score(-1)
                if(score.score < 0):
                    gm.state = gm.OVER
                    gm.setup()

        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(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)):
                    em.enemy_list[i].on = False
                    player.getMissileManager().missile_list[j].on = False
                    if (em.enemy_list[i].hit == False):
                        ex.create_explosion(em.enemy_list[i].x, em.enemy_list[i].y + 2)
                        em.enemy_list[i].hit = True
                        score.set_score(1)
                        if(score.score >= 30):
                            gm.state = gm.NEXT
                            gm.setup()

We have not started to create the game level class yet because we still need to create the final scene where that scene will pop up telling the player he has won the game and we will do that on the next chapter.

Create a game over scene for pygame project

In this article we are going to create a game over scene for the pygame project, we will use back the start scene class which we have created previously to render our game over scene by slightly modify it for the multi-scenes uses. Here is the modify version of the start scene class, as you can see we have passed in a state variable to the start scene class’s draw method which will be used to determine which scene to be rendered on the screen.

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

class StartScene(object):

    def __init__(self, scene):
        self.scene = scene
        self.button_image = 'Asset/button_play.png'
        self.bg_image = 'Asset/start.png'
        self.over_image = 'Asset/ove.png'
        self.bg_rect = Rect(0, 0, 660, 660)
        self.button_rect = Rect(0, 0,  306, 112)
        self.sprite = BgSprite(self.bg_image, self.bg_rect)
        self.sprite_over = BgSprite(self.over_image, self.bg_rect)
        self.sprite_button = GameSprite(self.button_image, self.button_rect)
        self.over_surface = self.sprite_over.getImage()  # get the game over 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.draw_pos = mt.Vector2(0, 0)
        self.draw_button_pos = mt.Vector2(177, 274)

    def draw(self, state):
        
        if(state == 0):
            self.scene.blit(self.surface, self.draw_pos) # draw a start scene sprite
        else:
            self.scene.blit(self.over_surface, self.draw_pos)  # draw a game over sprite
        self.scene.blit(self.button_surface, self.draw_button_pos)  # draw a button sprite
        pygame.display.flip()

Next we will need to modify the Game Manager class again by including an extra game over state variable and a new setup method into it.

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 *
import pygame

class GameManager(object):

    def __init__(self, scene):

        self.scene = scene
        self.start_scene = StartScene(scene)
        self.load_music()
        self.play_music()
        self.overlap_manager = Overlap()

        self.setup()

        #game state
        self.LOAD = 0
        self.GAME = 1
        self.OVER = 2

        self.state = self.LOAD

    def setup(self):

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

    def loop(self):

        if(self.state == self.LOAD or self.state == self.OVER):

            self.start_scene.draw(self.state)

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

            self.update()
            self.draw()

    def isAreaClick(self, pos):
        if (self.state == self.LOAD or self.state == self.OVER):
            self.rect = Rect(177, 274, 306, 112) # the position of the play button on the scene
            x, y = pos
            if(self.rect.collidepoint(x, y)):
                self.state = self.GAME


    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 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):
        self.background.draw()
        self.player.draw()
        self.enemy_manager.draw()
        self.explosion_manager.draw()
        self.score_manager.draw()
        pygame.display.flip()

We will pass in this class as the reference into the isOverlap method of the overlap manager which then will be used to access the state variable as well as reset the game objects to their original state by calling the newly created setup method of this class.

The last thing we need to do is to modify the 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 isOverlap(self, player, em, ex, score, gm):

        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
                if(em.enemy_list[i].hit == False):
                    ex.create_explosion(player.pos.x + 2, player.pos.y + 2)
                    em.enemy_list[i].hit = True
                    gm.state = gm.OVER
                    gm.setup()

        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
                ex.create_explosion(player.pos.x + 2, player.pos.y + 2)
                score.set_score(-1)
                if(score.score < 0):
                    gm.state = gm.OVER
                    gm.setup()

        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(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)):
                    em.enemy_list[i].on = False
                    player.getMissileManager().missile_list[j].on = False
                    if (em.enemy_list[i].hit == False):
                        ex.create_explosion(em.enemy_list[i].x, em.enemy_list[i].y + 2)
                        em.enemy_list[i].hit = True
                        score.set_score(1)

The game over scene will be loaded and the game objects will be recreated whenever the player collides with the enemy ship or the player strength falls below zero.

With that done we are now ready to move on to the next stage of the project, which is to create a level manager class to manage all the game levels in this game. If you have not yet subscribed to this website then do make sure to click on the red bell button below this post so you will get a first hand notification whenever a new article has been posted. This pygame project is not yet complete and there are still more articles related to this topic will be posted soon so make sure you subscribe to this website by clicking on that red bell button below if you want to read more articles about the pygame subject!

If you are following this tutorial from the beginning then your pycharm file explorer area should now has all these files below.

The game graphic area
All the game graphics
All the game project files
All the game project files

It is time to move on to the next chapter, see you there!

Create a game’s start scene for pygame project

In this article we are going to create a start scene for our pygame project. The start scene itself looks really simple but the process to render the start scene will involve the modification of a few files.

First of all, lets create the start scene class which will render a background and a play button on the game scene. When we click on that play button the game will start.

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

class StartScene(object):

    def __init__(self, scene):
        self.scene = scene
        self.button_image = 'Asset/button_play.png'
        self.bg_image = 'Asset/bg.png'
        self.bg_rect = Rect(0, 0, 660, 660)
        self.button_rect = Rect(0, 0,  306, 112)
        self.sprite = BgSprite(self.bg_image, self.bg_rect)
        self.sprite_button = GameSprite(self.button_image, self.button_rect)
        self.surface = self.sprite.getImage()  # get the background sprite surface
        self.button_surface = self.sprite_button.getImage() # get the button sprite surface
        self.draw_pos = mt.Vector2(0, 0)
        self.draw_button_pos = mt.Vector2(177, 274)

    def draw(self):
        self.scene.blit(self.surface, self.draw_pos) # draw a background sprite
        self.scene.blit(self.button_surface, self.draw_button_pos)  # draw a button sprite
        pygame.display.flip()

Next we will create an instance of the above class in our Game Manager class. Besides that we will do the following.

1) create a new loop method for the Game Manager class which will be called in the main game file to update and draw the objects on the game scene.
2) create the loading state and the game state constant variable together with the state variable which is used to determine whether the game manager should load the start scene or load the game scene.
3) create the isAreaClick method to determine whether the player has clicked on the start scene play button or not, if yes then the game state will change from loading state to gaming state and the game will start.

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 *
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.explosion_manager = ExplosionManager(self.scene)
        self.score_manager = Score(self.scene)
        self.start_scene = StartScene(scene)
        self.load_music()
        self.play_music()

        #game state
        self.LOAD = 0
        self.GAME = 1

        self.state = self.LOAD

    def loop(self):

        if(self.state == self.LOAD):

            self.start_scene.draw()

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

            self.update()
            self.draw()

    def isAreaClick(self, pos):
        if (self.state == self.LOAD): # if it is loading state then response to the click event
            self.rect = Rect(177, 274, 306, 112) # the position of the play button on the scene
            x, y = pos
            if(self.rect.collidepoint(x, y)):
                self.state = self.GAME


    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 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.iseOverlap(self.player, self.enemy_manager, self.explosion_manager, self.score_manager)

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

The last file we need to edit is the main file where we will add in the click event so we can find out whether the player has clicked on the play button or not. We will also remove the update and the draw method from the Game Manager class and replace them with a single loop method which we have talked about previously.

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)

        elif event.type == pygame.MOUSEBUTTONDOWN:
            # 1 is the left mouse button
            if event.button == 1:
                game_manager.isAreaClick(event.pos)

    game_manager.loop()

We will continue to modify the Game Manager class and create a game over scene class in the next chapter. If you want to know when will this website posts a new post then don’t forget to click on the bell notification button below this website.

Create a score manager class for pygame project

In this article we will create a score manager class to render the player score on the scene for our pygame project. At the moment we will only increase the score of the player each time the player’s missile hits the enemy ship and deduct the player score each time the player gets hit by the enemy missile, in the future we will introduce more features into the score manager class but for now lets just create a simple score manager class so we can edit it later on. Here is the score manager class.

import pygame.font as txt
from pygame.locals import *

class Score(object):

    def __init__(self, scene):

        self.score = 0
        self.scene = scene
        self.rect = Rect(20,20, 100, 30)
        self.font = txt.Font(None, 30)
        self.score_text = "Score : " + str(self.score)

    def set_score(self, score):

        self.score += score
        self.score_text = "Score : " + str(self.score)

    def draw(self):

        self.text = self.font.render(self.score_text, 1, (255, 255, 255))
        self.scene.blit(self.text, self.rect)

The set score method will be called in the overlap object’s iseOverlap method each time the player gets hit by the enemy missile or the enemy ship gets hit by the player missile. We will pass the score manager object into the iseOverlap method of the Overlap object in each game loop from the Game Manager class.

Lets edit the Game Manager class by creating a new score manager object and then pass the score manager object into the iseOverlap method of the Overlap object in each game loop. We will then call the score manager to draw the new score on the scene in the draw method of the Game Manager.

from Player import Player
from Background import Background
from EnemyManager import EnemyManager
from Overlap import Overlap
from ExplosionManager import ExplosionManager
from Score import Score
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.explosion_manager = ExplosionManager(self.scene)
        self.score_manager = Score(self.scene)
        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()
        self.explosion_manager.explosion_update()

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

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

The Overlap method just needs slightly modification.

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, ex, score):

        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
                if(em.enemy_list[i].hit == False):
                    ex.create_explosion(player.pos.x + 2, player.pos.y + 2)
                    em.enemy_list[i].hit = True

        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
                ex.create_explosion(player.pos.x + 2, player.pos.y + 2)
                score.set_score(-1)

        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(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)):
                    em.enemy_list[i].on = False
                    player.getMissileManager().missile_list[j].on = False
                    if (em.enemy_list[i].hit == False):
                        ex.create_explosion(em.enemy_list[i].x, em.enemy_list[i].y + 2)
                        em.enemy_list[i].hit = True
                        score.set_score(1)

Here is the result from the above program.

score manager in action
score manager in action

We will revisit the score manager again when we need it but for now it is time to move on to the next topic.

Create an explosion manager and explosion class for pygame project

In this article we will create an explosion manager as well as an explosion class to manage the on scene explosions but first of all lets watch the raw video below which shows the explosions on the game scene.

Before we create the above classes, we will create one single explosion sprite sheet which contains many explosion stages. We will then render each part of the sprite sheet with the help of the timer variable inside the explosion class.

Here is the explosion sprite sheet which we are using in this game.

Explosion
Explosion Sprite Sheet

Here is the explosion class.

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

class Explosion(object):

    def __init__(self, ex_surface, x, y):
        self.on = True
        self.ex_surface = ex_surface
        self.x = x
        self.y = y
        self.ex_pos = mt.Vector2(self.x, self.y)
        self.count = 0
        self.width = 64
        self.height = 64
        self.rect = Rect(self.count * self.width, 0, self.width, self.height)
        self.timer = 0

    def update(self):

        if(self.count <= 9):
            
            if(self.timer > 16):
                self.count += 1
                self.rect = Rect(self.count * self.width, 0, self.width, self.height)
                self.ex_pos = mt.Vector2(self.x, self.y)
                self.timer = 0
            else:
                self.timer += 1
        else:
            self.count = 0
            self.on = False
            self.timer = 0
            self.rect = Rect(self.count * self.width, 0, self.width, self.height)

As you can see we will constantly update the rect variable which will be used by the scene object to draw only a portion of the sprite explosion’s stage from the sprite sheet until all the explosion’s stages have been drawn on the scene which we will then remove the explosion object from the explosion main list. The timer variable is uses to control the creation speed of the new rectangle object so we will see a smooth stage transformation process on the game scene.

And here is the explosion manager class.

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

class ExplosionManager(object):

    def __init__(self, scene):

        self.image = 'Asset/explosion.png'
        self.scene = scene
        self.width = 640
        self.height = 64
        self.explosion_count = 10
        self.count = 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.explosion_object_pool = Objectpool(self.explosion_count)
        self.explosion_list = []

    def create_explosion(self, x, y):

        if (self.explosion_object_pool.getSize() > 0):
            self.explosion_list.append(self.explosion_object_pool.obtain_missile(x, y))
        else:
            self.explosion_list.append(Explosion(self.sprite_surface, x, y))

    def explosion_update(self):

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

    def draw(self):

        # blit the explosion on  the scene
        for i in range(len(self.explosion_list)):
            self.scene.blit(self.explosion_list[i].ex_surface, self.explosion_list[i].ex_pos, self.explosion_list[i].rect)

The methods within the above class are almost the same as the methods use by the other manager classes, as you can see we have created an explosion pool object to recycle the explosion object just like what we did before in the other manager classes.

Finally we need to modify the Game Manager class and the Overlap class.

from Player import Player
from Background import Background
from EnemyManager import EnemyManager
from Overlap import Overlap
from ExplosionManager import ExplosionManager
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.explosion_manager = ExplosionManager(self.scene)
        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()
        self.explosion_manager.explosion_update()

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

    def draw(self):
        self.background.draw()
        self.player.draw()
        self.enemy_manager.draw()
        self.explosion_manager.draw()
        pygame.display.flip()
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, ex):

        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
                if(em.enemy_list[i].hit == False):
                    ex.create_explosion(player.pos.x + 2, player.pos.y + 2)
                    em.enemy_list[i].hit = True

        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
                ex.create_explosion(player.pos.x + 2, player.pos.y + 2)

        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(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)):
                    em.enemy_list[i].on = False
                    player.getMissileManager().missile_list[j].on = False
                    if (em.enemy_list[i].hit == False):
                        ex.create_explosion(em.enemy_list[i].x, em.enemy_list[i].y + 2)
                        em.enemy_list[i].hit = True

Besides the above, we also need to include a hit variable in the enemy class and set it to false so the explosion will not happen twice due to many time of contact between the enemy ship and the same missile as well as the enemy ship and the player ship during the game. Also don’t forget to set the hit variable of the enemy to false again within the obtain method of the object pool class.

That is it, after passing the explosion manager into the Overlap class we can now create an explosion object whenever there is any contact happens between the game objects on the scene.

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.