Game Making with Python and Pygame Part 6

in #python5 years ago

Adding Player Controls to a Sprite

Game Making with Python and Pygame Part 6

See the previous parts linked at the bottom of this post if you haven't already.


We're going to start with a slightly different version of the code, with the ball code removed and replaced with a Player class that loads up a player.png that looks like this:

player
Image by Author - Amos1969 - Dave A

I've also taken away the image fro the background and replaced it with a fill colour, notice how instead of calling blit every time, instead we call fill with the colour.

import sys
import pygame

WIDTH = 800
HEIGHT = 600

class MainWindow:
    def __init__(self):
        pygame.init()

        self.player = Player(50, 50)

        self.DISPLAYSURF = pygame.display.set_mode((WIDTH, HEIGHT))
        self.purple = (150, 0, 220)
        self.DISPLAYSURF.fill(self.purple)
        pygame.display.set_caption('Look At My Rock and Ball - Game Making Part 6')

        self.clock = pygame.time.Clock()
        self.time_counter = 0

    def main_game_loop(self):
        while True:
            self.time_counter += self.clock.tick()
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    pygame.quit()
                    sys.exit()
            if self.time_counter > 15:
                self.DISPLAYSURF.fill(self.purple)
                self.player.draw(self.DISPLAYSURF)
                self.time_counter = 0
            pygame.display.update()

class Player:
    def __init__(self, x=0, y=0):
        self.image = pygame.image.load("player.png")
        self.image_rect = self.image.get_rect()
        self.image_rect.topleft = (x, y)

    def update(self):
        pass


    def draw(self, a_surface):
        a_surface.blit(self.image, self.image_rect)

game = MainWindow()
game.main_game_loop()

The first thing we're going ot do is add a move right method to our Player class. This will move the Player sprite 5 pixels to the right anytime it's called. We're going to use the move method on the rect again, but give it a tuple of (1, 0) for the movement. Initially the player will be able to take the sprite off the screen. Change the Player class so that it looks like this.

class Player:
    def __init__(self, x=0, y=0):
        self.image = pygame.image.load("player.png")
        self.image_rect = self.image.get_rect()
        self.image_rect.topleft = (x, y)

    def move_right(self):
        self.image_rect.move((1, 0))

    def draw(self, a_surface):
        a_surface.blit(self.image, self.image_rect)

On its own this will actually do nothing, we also need to check for a keypress. To begin with lets just call the move right method every time we go through the main loop to check that the image moves and updates correctly.

class MainWindow:
    def __init__(self):
        pygame.init()

        self.player = Player(50, 50)

        self.DISPLAYSURF = pygame.display.set_mode((WIDTH, HEIGHT))
        self.purple = (150, 0, 220)
        self.DISPLAYSURF.fill(self.purple)
        pygame.display.set_caption('Look At My Rock and Ball - Game Making Part 6')

        self.clock = pygame.time.Clock()
        self.time_counter = 0

    def main_game_loop(self):
        while True:
            self.time_counter += self.clock.tick()
            self.player.move_right()
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    pygame.quit()
                    sys.exit()
            if self.time_counter > 15:
                self.DISPLAYSURF.fill(self.purple)
                self.player.draw(self.DISPLAYSURF)
                self.time_counter = 0
            pygame.display.update()

Run it and you should see your player sprite go zooming out of the window to the right (for some value of zoom depending on your machine). First we're going to fix things so that the sprite can't go past the edge of the screen. Change the move_right() method so that it won't let the player sprite go off the screen.

class Player:
    def __init__(self, x=0, y=0):
        self.image = pygame.image.load("player.png")
        self.image_rect = self.image.get_rect()
        self.image_rect.topleft = (x, y)

    def move_right(self):
        self.image_rect = self.image_rect.move((1, 0))
        if self.image_rect.right > WIDTH:
            self.image_rect.right = WIDTH

    def draw(self, a_surface):
        a_surface.blit(self.image, self.image_rect)

Now we need to make it so that pressing the right arrow key calls the move_right() method. To achieve this we need to add some code to the pygame event loop (the for loop that's in the main game loop) first we check if we have a pygame.KEYDOWN event (ie a key has been pressed), then we check which key has been pressed and if it's the correct one we call the move_right() method. Change the MainWindow class so that it looks like this:

class MainWindow:
    def __init__(self):
        pygame.init()
        self.player = Player(50, 50)

        self.DISPLAYSURF = pygame.display.set_mode((WIDTH, HEIGHT))
        self.purple = (150, 0, 220)
        self.DISPLAYSURF.fill(self.purple)
        pygame.display.set_caption('Look At My Rock and Ball - Game Making Part 6')

        self.clock = pygame.time.Clock()
        self.time_counter = 0

    def main_game_loop(self):
        while True:
            self.time_counter += self.clock.tick()
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    pygame.quit()
                    sys.exit()
                if event.type == pygame.KEYDOWN:
                    if event.key == pygame.K_RIGHT:
                        self.player.move_right()
            if self.time_counter > 15:
                self.DISPLAYSURF.fill(self.purple)
                self.player.draw(self.DISPLAYSURF)
                self.time_counter = 0
            pygame.display.update()

If you run this code, then it will work (as long as you press the right arrow) but you'll have to repeatedly press the right arrow key to get the sprite to move. To combat this we need to make it so that when we hold a key down, after a given number of milliseconds the key repeats. We need to add the line pygame.key.set_repeat(3, 3) somewhere in our code. Basically this tells the program to wait 3 milliseconds before the keypress is repeated the first time, then waiting for a further 3 milliseconds each time. It needs to run after the pygame.init() method so we're just going to put it in the MainWindow constructor on the line following that.

class MainWindow:
    def __init__(self):
        pygame.init()
        pygame.key.set_repeat(3, 3)
        self.player = Player(50, 50)

        self.DISPLAYSURF = pygame.display.set_mode((WIDTH, HEIGHT))
        self.purple = (150, 0, 220)
        self.DISPLAYSURF.fill(self.purple)
        pygame.display.set_caption('Look At My Rock and Ball - Game Making Part 6')

        self.clock = pygame.time.Clock()
        self.time_counter = 0

    def main_game_loop(self):
        while True:
            self.time_counter += self.clock.tick()
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    pygame.quit()
                    sys.exit()
                if event.type == pygame.KEYDOWN:
                    if event.key == pygame.K_RIGHT:
                        self.player.move_right()
            if self.time_counter > 15:
                self.DISPLAYSURF.fill(self.purple)
                self.player.draw(self.DISPLAYSURF)
                self.time_counter = 0
            pygame.display.update()

If this is too quick or slow, then you can try changing the values. Test it out, make sure everything works, then we need to implement similar methods for left, up and down key presses. The full code, along with these 3 methods is shown below.

import sys
import pygame

WIDTH = 800
HEIGHT = 600

class MainWindow:
    def __init__(self):
        pygame.init()
        pygame.key.set_repeat(3, 3)
        self.player = Player(50, 50)

        self.DISPLAYSURF = pygame.display.set_mode((WIDTH, HEIGHT))
        self.purple = (150, 0, 220)
        self.DISPLAYSURF.fill(self.purple)
        pygame.display.set_caption('Look At My Rock and Ball - Game Making Part 6')

        self.clock = pygame.time.Clock()
        self.time_counter = 0

    def main_game_loop(self):
        while True:
            self.time_counter += self.clock.tick()
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    pygame.quit()
                    sys.exit()
                if event.type == pygame.KEYDOWN:
                    if event.key == pygame.K_RIGHT:
                        self.player.move_right()
                    if event.key == pygame.K_LEFT:
                        self.player.move_left()
                    if event.key == pygame.K_UP:
                        self.player.move_up()
                    if event.key == pygame.K_DOWN:
                        self.player.move_down()
            if self.time_counter > 15:
                self.DISPLAYSURF.fill(self.purple)
                self.player.draw(self.DISPLAYSURF)
                self.time_counter = 0
            pygame.display.update()

class Player:
    def __init__(self, x=0, y=0):
        self.image = pygame.image.load("player.png")
        self.image_rect = self.image.get_rect()
        self.image_rect.topleft = (x, y)

    def move_right(self):
        self.image_rect = self.image_rect.move((1, 0))
        if self.image_rect.right > WIDTH:
            self.image_rect.right = WIDTH

    def move_left(self):
        self.image_rect = self.image_rect.move((-1, 0))
        if self.image_rect.left < 0:
            self.image_rect.left = 0

    def move_up(self):
        self.image_rect = self.image_rect.move((0, -1))
        if self.image_rect.top < 0:
            self.image_rect.top = 0

    def move_down(self):
        self.image_rect = self.image_rect.move((0, 1))
        if self.image_rect.bottom > HEIGHT:
            self.image_rect.bottom = HEIGHT

    def draw(self, a_surface):
        a_surface.blit(self.image, self.image_rect)

game = MainWindow()
game.main_game_loop()

Currently we can't move diagonally, and we're going to leave it like that, for now, we may come back and try and fix this later, or not, depending on whether the game we decide to implement needs it or not. We may also refactor our code to see if there are other ways to achieve the same goal. But this is the end of Part 6.

In Part 7 we'll bring back some randomly moving sprites and implement a simple dodge the balls style game, which will introduce collision detection techniques.


Like and follow if you're enjoying these. If you have any comments or suggestions for improvements or things you'd like it do, let me know in the comments.


Previous parts:

Part 1 - How to get set up with an up-to-date version of Pygame: Part 1

Part 2 - How to make a window appear using basic code: Part 2

Part 3 - Refactoring the code into a class and adding a background image: Part 3

Part 4 - Added a moving sprite to the window: Part 4

Part 5 - Refactoring the ball sprite into a class of its own: Part 5

Coin Marketplace

STEEM 0.20
TRX 0.14
JST 0.030
BTC 68854.36
ETH 3283.36
USDT 1.00
SBD 2.67