Game Making with Python and Pygame Part 4

in #python5 years ago

Adding Some Moving Sprites

Game Making with Python and Pygame Part 4

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


We'll start by just loading in a ball png, which measures 50 x 50 pixels. In this post we'll just have the ball contained within the MainWindow class, but we'll refactor it into a separate class in a later post. To begin with we'll add in code to load up the ball image and create a rect for it. We'll do it in the __init__() method for now. We also need to add in a line to blit() the ball image onto the ball_rect in the main game loop.

import sys
import pygame

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

        self.ball = pygame.image.load("ball.png")
        self.ball_rect = self.ball.get_rect()

        self.background = pygame.image.load("myrock.jpg")
        self.background_rect = self.background.get_rect()

        self.DISPLAYSURF = pygame.display.set_mode(self.background.get_size())
        pygame.display.set_caption('Look At My Rock - Game Making Part 4')

        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 > 100:
                self.DISPLAYSURF.blit(self.background, self.background_rect)
                self.DISPLAYSURF.blit(self.ball, self.ball_rect)
                self.time_counter = 0
            pygame.display.update()

game = MainWindow()
game.main_game_loop()

When we run the code, the window will display as it did in the previous part but will have the image of the ball, in the top left-hand corner. We can set the position of the ball when we first load it in by giving values to the top and left of the ball_rect object. Try experimenting with the numbers.

import sys
import pygame

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

        self.ball = pygame.image.load("ball.png")
        self.ball_rect = self.ball.get_rect()
        self.ball_rect.left = 100
        self.ball_rect.top = 150

        self.background = pygame.image.load("myrock.jpg")
        self.background_rect = self.background.get_rect()

        self.DISPLAYSURF = pygame.display.set_mode(self.background.get_size())
        pygame.display.set_caption('Look At My Rock - Game Making Part 4')

        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 > 100:
                self.DISPLAYSURF.blit(self.background, self.background_rect)
                self.DISPLAYSURF.blit(self.ball, self.ball_rect)
                self.time_counter = 0
            pygame.display.update()

game = MainWindow()
game.main_game_loop()

The rect object has lots of parts that we can pass values to in order to change its position: top, left, bottom, right, topleft, bottomleft, topright, bottomright, midtop, midleft, midbottom, midright, center, centerx, centery. If we give them suitable values then we can move the image to a suitable position in the window. Experiment with using different attributes to position the ball.

Attributes such as topleft take coordinates, rather than single values. The x (horizontal) coordinate is measured from the left-hand edge of the window (exactly the same as coordinates in Maths) but the y (vertical) coordinate is measured from the top edge of the window (the opposite to coordinates in Maths).

import sys
import pygame

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

        self.ball = pygame.image.load("ball.png")
        self.ball_rect = self.ball.get_rect()
        self.ball_rect.topleft = (170, 50)

        self.background = pygame.image.load("myrock.jpg")
        self.background_rect = self.background.get_rect()

        self.DISPLAYSURF = pygame.display.set_mode(self.background.get_size())
        pygame.display.set_caption('Look At My Rock - Game Making Part 4')

        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 > 100:
                self.DISPLAYSURF.blit(self.background, self.background_rect)
                self.DISPLAYSURF.blit(self.ball, self.ball_rect)
                self.time_counter = 0
            pygame.display.update()

game = MainWindow()
game.main_game_loop()

The tuple which is assigned to topleft can either have brackets around it as in the code or miss them out, as when assigning values in Python this will still create a tuple.

Pygame rect objects have a move() method, if we pass it a velocity object which is a list of two values (x and y components), then this will automatically update the position of the rect every time it is called. If we set the velocity to [5, 4] (it needs to be a list so we can change the value later), change the counter time to update every 15 milliseconds (60fps is a frame every 16 2/3 milliseconds) and add the move method into the body of the if statement, before the blit calls, when the code is run you should see the ball drift off to the edge of the screen. At the minute the ball will travel off the edge, never to be seen again (until we rerun the code anyhow ;-) ).

import sys
import pygame

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

        self.ball = pygame.image.load("ball.png")
        self.ball_rect = self.ball.get_rect()
        self.ball_rect.topleft = (170, 50)

        self.velocity = [5, 4]

        self.background = pygame.image.load("myrock.jpg")
        self.background_rect = self.background.get_rect()

        self.DISPLAYSURF = pygame.display.set_mode(self.background.get_size())
        pygame.display.set_caption('Look At My Rock - Game Making Part 4')

        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.ball_rect = self.ball_rect.move(self.velocity)
                self.DISPLAYSURF.blit(self.background, self.background_rect)
                self.DISPLAYSURF.blit(self.ball, self.ball_rect)
                self.time_counter = 0
            pygame.display.update()

game = MainWindow()
game.main_game_loop()

We can make the ball bounce off the edges of the screen quite easily by checking each time through whether the edges of the ball are outside the edge of the window, if they are then changing the sign of the horizontal or vertical component of the speed will reverse the direction the ball goes in accordingly. This means if the right-hand edge of the ball ends up outside of the right-hand edge of the window, changing the x value to -x will make the ball appear to bounce off that edge, and will have a similar effect vertically. The only problem is that occasionally the ball will become stuck in a corner of the window.

import sys
import pygame

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

        self.ball = pygame.image.load("ball.png")
        self.ball_rect = self.ball.get_rect()
        self.ball_rect.topleft = (170, 50)

        self.velocity = [5, 4]

        self.background = pygame.image.load("myrock.jpg")
        self.background_rect = self.background.get_rect()

        self.width = self.background_rect.width
        self.height = self.background_rect.height

        self.DISPLAYSURF = pygame.display.set_mode(self.background.get_size())
        pygame.display.set_caption('Look At My Rock - Game Making Part 4')

        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.ball_rect = self.ball_rect.move(self.velocity)

                if self.ball_rect.left < 0 or self.ball_rect.right > self.width:
                    self.velocity[0] = -self.velocity[0]
                if self.ball_rect.top < 0 or self.ball_rect.bottom > self.height:
                    self.velocity[1] = -self.velocity[1]

                self.DISPLAYSURF.blit(self.background, self.background_rect)
                self.DISPLAYSURF.blit(self.ball, self.ball_rect)
                self.time_counter = 0
            pygame.display.update()

game = MainWindow()
game.main_game_loop()

We can speed up the ball by increasing the size of the values for the speed or decreasing the value for the counter. We could also add in a second ball with new coordinates, and a different velocity. We would then need to add in some code to check its position and update the velocity accordingly if necessary.

We'll leave Part 4 there. Next time we'll come back and refactor it so that the ball is in a separate class, and instantiate multiple copies of it in the window. Depending on how much work that takes we may also make it so that the player can control the movement of one of the sprites, or possibly save that for the following post.

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

Coin Marketplace

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