Moving the player object in Pygame

In the last chapter we have created the animation effect for the player object and in this chapter, we will move the player object in the x-axis. We will leave the wall and boundary collision detection mechanism to the next chapter. In the last chapter we have already linked up the keyboard events with the game manager class and in this chapter, we only need a slight modification to move the player across the scene when the left or the right arrow key has been pressed. One of the problems with the pygame event module is that we need to activate the repeated event detection process by our-self with this single line of code before the module can send the repeated keypress event (which means when someone is holding the same key on the keyboard) to us.

pygame.key.set_repeat(100, 40)

By setting the delay and interval in the pygame.key.set_repeat method the program will continue to receive the information of the key which the player has pressed on at the moment, this is very important because if the key repeated event has been disabled then the program will only get the keypress’s feedback once after the user has pressed on any key on the keyboard and will not receive the key pressed event again even-though the user has held on to that same key after he has pressed on it. We need to continuously receive the feedback from the pygame key event module in order to move the player smoothly across the canvas. Below is the modified version of the main file.

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

pygame.init()

size = width, height = 640, 640
pygame.display.set_caption("Amaze Boy")  # set the title of the window
screen = pygame.display.set_mode(size)
game_manager = GameManager(screen)
rect_exit = Rect(229, 456, 200, 53)  # the position of the exit button on the home scene
running = True
pygame.key.set_repeat(100, 40)

while running:

    for event in pygame.event.get():
        # when the user clicks on the 'x'
        if event.type == pygame.QUIT:
            game_manager.save_level()
            running = False

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

            if (game_manager.state == 1):

                if event.key == K_LEFT:
                    game_manager.set_player_x(-2)
                elif event.key == K_RIGHT:
                    game_manager.set_player_x(2)
                elif event.key == K_UP:
                    game_manager.set_player_y(-2)
                elif event.key == K_DOWN:
                    game_manager.set_player_y(2)

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

    game_manager.loop()

Next, we will modify the game manager class by including the boy sprite update method in the update method of this class.

from EnemyManager import EnemyManager
from Overlap import Overlap
from ExplosionManager import ExplosionManager
from Score import Score
from StartScene import StartScene
from pygame.locals import *
from LevelManager import LevelManager
import pygame
import webbrowser
from Scene import Scene
from BackGroundSprite import BackGroundSprite
from BoySprite import BoySprite

class GameManager(object):

    def __init__(self, scene):

        self.scene = scene

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

        self.pause = False # flag to pause the game

        self.game_scene = Scene(self.scene)

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

        self.state = self.LOAD

    def setup(self, game_level):

        self.game_level = game_level
        self.score_manager = Score(self.scene, self.level_manager)
        self.background = BackGroundSprite(game_level, self.scene)
        self.enemy_manager = EnemyManager(self.scene, game_level)
        self.boy_sprite = BoySprite(self.scene, game_level)
        self.explosion_manager = ExplosionManager(self.scene)

    def loop(self):

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

            self.update()
            self.draw()

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

            self.start_scene.draw(self.state)

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

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

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

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

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

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

    def set_pause(self, pause):

        self.pause = pause

        if(self.pause == True):

            self.state = self.PAUSE

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

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

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

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

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

    def update(self):
        self.enemy_manager.update()
        self.boy_sprite.update()
        #self.isOverlap()
        #self.explosion_manager.explosion_update()

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

    def draw(self):
        if(self.state == self.GAME):
            self.background.draw()

            #self.enemy_manager.update()
            #self.explosion_manager.draw()
            #self.score_manager.draw()
            self.boy_sprite.draw()
            self.enemy_manager.draw()
            pygame.display.flip()

Finally we will slightly modify the boy sprite class.

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

class BoySprite(object):

    def __init__(self, scene, level):

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

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

    # set the x and y direction for the player object

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

            if (self.frame > 5):
                self.frame = 1
            self.boy_sprite = self.boy_image_sprite_left
        elif(x > 0):
            self.frame += 1

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

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

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

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

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

            for column in range(self.column):

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

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

    def draw(self):

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

Just in case you wonder why the boy’s sprite has such a wield frame number, I will leave two sprite sheets of the boy object below for you to figure it out.

bright.png
bleft.png

If you run the above program and press the left or right key on your keyboard you will see the below outcome. As I have mentioned earlier the boy’s boundary detection part will be on the next chapter.

Hope you like this post, like, share or tweet!