Playing background music with Pygame

Playing background music with Pygame is relatively simple with just a few lines of code. Before you can start playing a background music you will need to initialize the pygame.mixer interface first.

pygame.init()
pygame.mixer.pre_init(frequency, size, stereo, buffer)

As you can see from above the init method takes in a few parameters.

1) frequency is the sample rate of the audio playback and has the same meaning as the sample rate of music files.
2) size is the size, in bits, of the audio samples for the playback.
3) stereo only has two options : 1 for mono sound or 2 for stereo sound.
4) buffer is the number of samples that are buffered for playback.

Below is an example of how to initialize the mixer.

pygame.mixer.pre_init(44100, 16, 2, 5000)

In the above example we set the mixer to 16-bit, 44100Hz stereo music.

Now to play the background music all you need is these two lines.

sound1 = pygame.mixer.Sound("music.ogg")
channel1 = sound1.play(-1)

The first line takes the music file and create the sound object. The next line play the background music with an infinite number of time.

The channel object returns by the play method can then be used in other part of the code, for example we can

channel1.queue(sound1)

set up a queue by passing in a sound object which will be played after the main music has stopped.

How to use the mouse input in Pygame

Pygame allows us to get the mouse input with the pygame.mouse module. Below are three pygame.mouse module methods that we will often use to find the mouse input.

1) pygame.mouse.get_pressed will returns a tuple contains three 0 or 1 values for the left, middle, and right mouse buttons. If the button is pressed then the value will become 1 or else it will become 0.

2) pygame.mouse.get_pos will return the mouse coordinates as a tuple of the x and y values.

3) pygame.mouse.get_rel will return the relative mouse movement (or mickeys) as a tuple with the x and y relative movement.

Below script will print out the x and y coordinate of the mouse on the screen with the pygame.mouse.get_pos method.

#!/usr/bin/env python

import pygame
from pygame.locals import *
from sys import exit

pygame.init()

screen = pygame.display.set_mode((640, 480), 0, 32)
font = pygame.font.SysFont("arial", 17);
font_height = font.get_linesize()

while True:
    for event in pygame.event.get():
        if event.type == QUIT:
            exit()
    screen.fill((255, 255, 255))
    
    x, y = pygame.mouse.get_pos()
    
    text_surface = font.render("x coordinate : " + str(x) + " y coordinate : " + str(y), True, (0,0,0))
    screen.blit(text_surface, (10, font_height))
    
    pygame.display.update()

Mouse is more wonderful as compared to keyboard so make sure you have included the mouse factor in your game design. This article will conclude the keyboard and mouse chapter and now we are ready to move on into other chapter in Pygame.

Moving the sprite with Vector in Pygame

In this chapter we are going to use our newly created Vector2D class to move the game sprite within a pygame screen. What we are doing here is to add up a vector with another vector which will then create a new vector that will be use as the sprite’s new position. If the user presses any of these keys on the keyboard : left arrow, right arrow, up arrow or the down arrow key then a new unit vector will be created and by multiplying that unit vector with the speed and time we will get a new vector which can then be added up to the old one and becomes the new position of the sprite object.

#!/usr/bin/env python

import pygame
from pygame.locals import *
from sys import exit
from vector2d import Vector2D

pygame.init()

boat = 'boat.png'

screen = pygame.display.set_mode((640, 480), 0, 32)
pygame.display.set_caption("Pygame Demo")

player = pygame.image.load(boat).convert_alpha()

clock = pygame.time.Clock()
player_pos = Vector2D(350, 350)
player_speed = 300.
v = Vector2D(0., 0.)

while True:
   
    for event in pygame.event.get():
        
        if event.type == QUIT:
            exit()
            
    pressed_keys = pygame.key.get_pressed()
        
    if pressed_keys[K_UP]:
        v = Vector2D(0., -1.) 
    elif pressed_keys[K_DOWN]:
        v = Vector2D(0., 1.) 
    elif pressed_keys[K_LEFT]:
        v = Vector2D(-1., 0.) 
    elif pressed_keys[K_RIGHT]:
        v = Vector2D(1., 0.)
            
    screen.fill((255, 255, 255))
    
    player_draw_pos = Vector2D(player_pos.x, player_pos.y)
    screen.blit(player, player_draw_pos)
    
    time_passed = clock.tick()
    time_passed_seconds = time_passed / 1000.0
            
    player_pos+= v * player_speed * time_passed_seconds   
    pygame.display.update()

With that we are almost done with the vector part of the pygame tutorial and ready for the next chapter in pygame so make sure you visit this blog everyday to learn the complete pygame tutorial!

Rotate an object in Pygame

Rotating an object in python Pygame is relatively simple as compared to html5 or Java, all we need to do is to rotate an object with this pygame method.

rotated_player = pygame.transform.rotate(player, player_rotation)

The player_rotation is the rotation angle of the sprite and player is the surface of that sprite. We will use the Vector2D class which we have previously created in the below script

player_draw_pos = Vector2D(player_pos.x-w/2, player_pos.y-h/2)
screen.blit(rotated_player, player_draw_pos)

to draw out the image and keep it in the memory but before that we need to turn the Vector2D class into a sub-class of the tuple class and overwrite the

__new__(cls, x=0.0, y=0.0)

method of the sub-class so the Vector2D class will return a tuple which can then be used inside the screen.blit method above.

Below is the revised edition of the Vector2D class.

import math

class Vector2D(tuple):
    
    def __new__(cls, x=0.0, y=0.0):
        return tuple.__new__(cls, (x, y))
    
    def __init__(self, x=0.0, y=0.0):
        self.x = x
        self.y = y
        
    def __str__(self):
        return "(%s, %s)"%(self.x, self.y)
    
    @classmethod
    def next_vector(cls, args):
        return cls(args[2]-args[0], args[3]-args[1])
    
    def get_magnitude(self):
        return math.sqrt( self.x**2 + self.y**2 )
    
    def normalize(self):
        magnitude = self.get_magnitude()
        self.x /= magnitude
        self.y /= magnitude
        
    # rhs stands for Right Hand Side
    def __add__(self, rhs):
        return Vector2D(self.x + rhs.x, self.y + rhs.y)
    
    def __sub__(self, rhs):
        return Vector2D(self.x - rhs.x, self.y - rhs.y)
    
    def __neg__(self):
        return Vector2D(-self.x, -self.y)
    
    def __mul__(self, scalar):
        return Vector2D(self.x * scalar, self.y * scalar)
    
    def __div__(self, scalar):
        return Vector2D(self.x / scalar, self.y / scalar)

Now let’s start to rotate an object with the below script.

#!/usr/bin/env python

import pygame
from pygame.locals import *
from sys import exit
from vector2d import Vector2D
from math import *

boat = 'boat.png'

pygame.init()

screen = pygame.display.set_mode((640, 480), 0, 32)
pygame.display.set_caption("Pygame Rotation Demo")

player = pygame.image.load(boat).convert_alpha()

clock = pygame.time.Clock()
player_pos = Vector2D(300, 250)

player_rotation = 0.
player_rotation_speed = 360. # 360 degrees per second

while True:
   
    for event in pygame.event.get():
        
        if event.type == QUIT:
            exit()
            
    pressed_keys = pygame.key.get_pressed()
        
    rotation_direction = 0.
        
    if pressed_keys[K_LEFT]:
        rotation_direction = -1.0
    if pressed_keys[K_RIGHT]:
        rotation_direction = +1.0
            
    screen.fill((255, 255, 255))
    
    rotated_player = pygame.transform.rotate(player, player_rotation) # Return the rotated_player surface object
    w, h = rotated_player.get_size()
    player_draw_pos = Vector2D(player_pos.x-w/2, player_pos.y-h/2)
    screen.blit(rotated_player, player_draw_pos)
    
    time_passed = clock.tick()
    time_passed_seconds = time_passed / 1000.0
    
    player_rotation += rotation_direction * player_rotation_speed * time_passed_seconds
            
    pygame.display.update()

Basically what the above script does is to rotate the sprite in the clockwise or anti-clockwise direction when we press the right or the left arrow key. We will also move the top-left corner of the sprite back by half before we draw our sprite in the memory, this move is required to make sure the sprite object will be drawn correctly.

Below is the outcome of the above program.

Create a Vector class in Pygame

What is Vector?

Suppose we want to move from point A to point B where point A is situated at (33.0, 35.0) and point B is at (55.0, 45.0) then Vector AB will be the different between these two points, or the x and the y distance between this two points is (x2-x1, y2-y1) or (55.0-33.0, 45.0-35.0).

Why do we need to create a vector class?

Vector module helps game developer to perform various operations, for example moves an object from point A to point B as well as find out the vector magnitude of that object, therefore it is always better if we can create a Vector module before we create our game.

Create a Vector2D class in python

Vector class is just like any other module class with methods that we can use to move an object or modify the property of that object.

import math

class Vector2D(object):
    
    def __init__(self, x=0.0, y=0.0):
        self.x = x
        self.y = y
        
    def __str__(self):
        return "(%s, %s)"%(self.x, self.y)
    
    @classmethod
    def next_vector(cls, args):
        return cls(args[2]-args[0], args[3]-args[1])
    
    def get_magnitude(self):
        return math.sqrt( self.x**2 + self.y**2 )
    
    def normalize(self): # find the unit vector
        magnitude = self.get_magnitude()
        self.x /= magnitude
        self.y /= magnitude
        
    # rhs stands for Right Hand Side
    def __add__(self, rhs):
        return Vector2D(self.x + rhs.x, self.y + rhs.y)
    
    def __sub__(self, rhs):
        return Vector2D(self.x - rhs.x, self.y - rhs.y)
    
    def __neg__(self):
        return Vector2D(–self.x, –self.y)
    
    def __mul__(self, scalar):
        return Vector2D(self.x * scalar, self.y * scalar)
    
    def __div__(self, scalar):
        return Vector2D(self.x / scalar, self.y / scalar)

A few methods above are the overload methods where they will be called when the Vector class instance performs certain operation, for example the __div__, __mul__, __sub__ and __add__ method will be called when we divide, multiply, subtract and add two vectors together. The __neg__ method will be called if we want to point a Vector in the opposite direction.

The __init__ method will be called at the moment we initialized the Vector2D’s instance and __str__ will be called when we print that object with the python print function.

The get_magnitude method will return the magnitude of the Vector and the normalize method will divide the x and the y length of the Vector with it’s magnitude.

Finally next_vector will take in the combine value of two tuples and return a new Vector2D object.

Create a separate python module with below script.

from vector2d import Vector2D

if __name__ == "__main__":
    A = (10.0, 20.0)
    B = (30.0, 35.0)
    C = (15.0, 45.0)
    AB = Vector2D.next_vector(A+B)
    BC = Vector2D.next_vector(B+C)
    AC = AB+BC
    print(AC)
    AC = Vector2D.next_vector(A+C)
    print(AC)

If you run the above module then you can see that when you add up two vectors AC = AB + BC the overload __add__ method of vector AB will be called which will then return a new Vector2D object. AC = Vector2D.next_vector(A+C) will create the same outcome as AC = AB + BC when we print the vector out with the print function. In this example the result is (5.0, 25.0).

The above Vector2D function will get you started where you can now include more methods into the Vector2D module for the future expansion purposes.

How to detect boundary in Pygame

When we design a game first thing we need to do is to make sure our game character stays within the game boundary. In order to make sure our game character will move within the game boundary we will create a set of rule such as if the top-left corner of that game character moves pass the x or the y boundary of the screen then we will need to reset the coordinate for the top-left corner of that game character accordingly. Below script will create a bouncing ball which will change color randomly and moves within the boundary of the screen.

import pygame
from pygame.locals import *
from sys import exit

from random import *

pygame.init()
screen = pygame.display.set_mode((640, 480), 0, 32)

clock = pygame.time.Clock()

x, y = 10., 10.
speed_x, speed_y = 100., 90.

circle_radius = 7
circle_pos = (int(x), int(y))


while True:
    
    for event in pygame.event.get():
        if event.type == QUIT:
            exit()
            
    random_color = (randint(100,255), randint(30,255), randint(155,255))
    screen.fill((255, 255, 255))
    
    pygame.draw.circle(screen, random_color, circle_pos, circle_radius)
    
    time_has_passed = clock.tick(30) #return the time delta after each frame
    time_has_passed_in_second = time_has_passed / 1000.0
    
    x += speed_x * time_has_passed_in_second
    y += speed_y * time_has_passed_in_second
    
    # If the ball goes off the edge of the screen,
    # reset it's position and then move it in the opposite direction
    if x > 640 - (circle_radius * 2):
        speed_x = -speed_x
        x = 640 - (circle_radius * 2)
    elif x < 0:
        speed_x = -speed_x
        x = 0.
    if y > 480 - (circle_radius * 2):
        speed_y = -speed_y
        y = 480 - (circle_radius * 2)
    elif y < 0:
        speed_y = -speed_y
        y = 0
        
    circle_pos = (int(x), int(y))
            
    pygame.display.update()

The script above also shows us that we can actually use the pygame.draw module to draw out our gaming character instead of loading graphic into the computer memory.

If you run the above script then you will see the below outcome!

Draw lines with Pygame

The pygame.draw.lines method which takes in 1) Screen surface 2) Line color 3) Boolean value to indicate whether should close the lines or not 4) Line coordinates and 5) Line width, will produce the below outcome.

Pygame draw lines
Pygame draw lines

Just like pygame.draw.line, there is also an antialiased version of pygame.draw.lines which will draw smooth lines on the screen.

The drawlines script is as follow.

import pygame
from pygame.locals import *
from sys import exit

pygame.init()
screen = pygame.display.set_mode((640, 480), 0, 32)

coordinate  = []

while True:
    
    for event in pygame.event.get():
        if event.type == QUIT:
            exit()
            
        if event.type == MOUSEMOTION:
            coordinate.append(event.pos)
            
    screen.fill((255, 255, 255))

    if len(coordinate)>1:
        pygame.draw.lines(screen, (0,255,0), False, coordinate, 3)
            
    pygame.display.update()

The script above will append a tuple which consists of x, y coordinate to the coordinate array every time we touch a point on the screen, the coordinate array will then be used in the pygame.draw.lines method.

Draw Arc with Pygame

Drawing arc with Pygame is just like drawing ellipse, the pygame.draw.arc method takes these arguments.

1) The screen surface
2) The color of that arc
3) The rectangle object where the arc will fit into
4) The starting angle of the arc
5) The ending angle of the arc
6) An optional line width of the arc

Below script will draw the arc which will fit in the entire width and height of the screen.

import pygame
from pygame.locals import *
from sys import exit

from math import pi

pygame.init()
screen = pygame.display.set_mode((640, 480), 0, 32)

while True:
    
    for event in pygame.event.get():
        if event.type == QUIT:
            exit()
            
    angle = 0.5*pi*2.
    screen.fill((255,255,255))
    pygame.draw.arc(screen, (0,0,0), (0,0,639,479), 0, angle, 3)
        
    pygame.display.update()

The above script will produce the following outcome.

Pygame arc
Pygame arc

Drawing an Ellipse with Pygame

Drawing an Ellipse with Pygame is just like drawing other shape, basically Pygame will stretch a circle to fit within a rectangle object specified by a tuple contains the top left corner of the rectangle and the width and height of that rectangle. Below is the entire script showing you how to draw an ellipse on the screen surface.

import pygame
from pygame.locals import *
from sys import exit

pygame.init()
screen = pygame.display.set_mode((640, 480), 0, 32)

while True:
    
    for event in pygame.event.get():
        if event.type == QUIT:
            exit()
            
        
        screen.fill((255,255,255))
        screen.lock()
        pygame.draw.ellipse(screen, (0,255,0), (30,30,200,300))
        screen.unlock()
        
            
    pygame.display.update()

The above script will produce the following outcome.

Pygame Ellipse
Pygame Ellipse

The pygame.draw.ellipse method takes in these parameters.

1) Screen surface to draw on it
2) Color tuple for ellipse
3) Rectangle tuple
4) An optional line width which if stated will create a hollow ellipse instead of a solid one

Draw a line with Pygame

In this article we will draw a new line with Pygame every time the user clicks on a new position on the screen. The method we will use here is the pygame.draw.line method which takes in these arguments:

1) The screen surface to draw on.
2) The color of the line.
3) The first point of the line.
4) The second point of the line.
5) An optional width value of the line.

The python script to draw the line is as follow:

import pygame
from pygame.locals import *
from sys import exit

pygame.init()
screen = pygame.display.set_mode((640, 480), 0, 32)

origin = (30, 30)

while True:
    
    for event in pygame.event.get():

        if event.type == QUIT:
            exit()
            
        if event.type == MOUSEBUTTONDOWN:
            screen.fill((255,255,255))
            screen.lock()
            pygame.draw.line(screen, (30, 0, 20), origin, event.pos, 2)
            screen.unlock()
        
            
    pygame.display.update()

Below is the outcome.

Pygame drawing line
Pygame drawing line

The line will change every time you click on the different place on the screen!

Besides the pygame.draw.line method, Pygame also offers the pygame.draw.aaline method which takes in the same parameters as pygame.draw.line but draws smoother line by using the antialiasing technique to draw the line!