Nemanja Grubor
15 Jul 2021
•
10 min read
In this article, we will talk about game development basics in Python. We will review the Pygame library.
Pygame library includes several modules with functions for drawing graphics, playing sounds, handling mouse input, etc.
The Python programs that you can write with Python's built-in functions only deal with the text through the print()
and input()
functions. Your program can display text on the screen and let the user type in the text from the keyboard. These types of programs have a command-line interface (CLI). These programs are limited because they can't display graphics, have colors, or use the mouse. These CLI programs only get input from the keyboard with the input()
function and even then, the user must press Enter before the program can respond to the input.
Pygame provides functions for creating programs with a graphical user interface (GUI). Instead of a text-based CLI, programs with a graphics-based GUI can show a window with images and colors.
The following program will display a black windows with the Hello World! caption.
import pygame, sys
from pygame.locals import *
pygame.init()
disp = pygame.display.set_mode((400, 300))
pygame.display.set_caption('Hello World!')
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
pygame.display.update()
Output:
The function pygame.display.set_mode
return the pygame.Surface
object for the window. A tuple in the argument tells the set_mode()
function how wide how high to make the window in pixels (400, 300).
A game loop is a loop where the code does the following:
Any time the user does one of several actions such as pressing a keyboard key or moving the mouse on the program's window, a pygame.event.Event
object is created by the Pygame library to record this event. We can find out which events have happened by calling the pygame.event.get()
function, which returns a list of pygame.event.Event
objects.
Any time the user does one of several actions, such as pressing a keyboard key or moving the mouse, a pygame.event.Event
object is created by the Pygame library to record this event. We can find out witch events have happened by calling the pygame.event.get()
function, which returns a list of pygame.event.Event
objects.
Event objects have a member variable named type
which tells us what kind of event the object represents. Pygame has a constant variable for each of possible types in the pygame.locals
modules. Since we used the from pygame.locals import *
form of the import
statement, wy only have to type QUIT
instead of pygame.locals.QUIT
.
If the Event object is a quit event, then the pygame.quit()
and sys.exit()
functions are called. The pygame.quit()
function deactivates the Pygame library.
Surface objects are objects that represent a rectangular 2D image. The Surface object returned by pygame.display.set_mode()
is called the display Surface.
In Pygame, we represent colors with tuples of three integers (RGB values). The first value in the tuple is how much red is in the color. An integer value of 0 means there is no red in this color, and the value of 255 means there is the maximum amount of red in the color. The second value is for green and the third value is for blue.
Because you can use any combination of 0 to 255 for each of the three primary colors, this means that Pygame can draw 16 777 216 different colors (256256256). However, if you try to use a number larger than 255 or a negative number, you will get an error.
You can mix the amount of red, green, and blue to form other colors. Here are the RGB values for a few common colors:
| Color | RGB Values |
|-----------|-----------------|
| Aqua | (0, 255, 255) |
| Black | (0, 0, 0) |
| Blue | (0, 0, 255) |
| Fuchsia | (255, 0, 255) |
| Gray | (128, 128, 128) |
| Green | (0, 128, 0) |
| Lime | (0, 255, 0) |
| Maroon | (128, 0, 0) |
| Navy Blue | (0, 0, 128) |
| Olive | (128, 128, 0) |
| Purple | (128, 0, 128) |
| Red | (255, 0, 0) |
| Silver | (192, 192, 192) |
| Teal | (0, 128, 128) |
| White | (255, 255, 255) |
| Yellow | (255, 255, 0) |
You can get the transparent shading effect by adding a fourth 0 to 255 integer value to your color values. This value is known as the alpha value. It is a measure of how opaque color is.
In order to draw using transparent colors, you must create a Surface object with the convert_alpha()
method. For example, the following code creates a Surface object that transparent colors can be drawn on:
surf = disp.convert_alpha()
It is important to note that you cannot use transparent colors on Surface objects not returned from a convert_alpha()
call, including the display Surface that was returned from pygame.display.set_mode()
.
You need to know how to represent a color because Pygame's drawing functions need a way to know which color you want to draw with. A tuple of three or four integers is one way. Another way is a pygame.Color()
object. You can create Color objects by calling the pygame.Color()
constructor function and passing either three or four integers. You can store this Color object in variables just like you can store tuples in variables.
Example:
import pygame
pygame.Color(255, 0, 0)
myColor = pygame.Color(255, 0 , 0, 128)
myColor == (255, 0, 0, 128)
Any drawing function in Pygame that has a parameter for color can have either a tuple form or Color object form of color passed for it. Even though they are different data types, a Color object is equal to a tuple of four integers if they both represent the same color.
Pygame has two ways to represent rectangular areas. The first is a tuple of four integers:
The second way is a pygame.Rect
object. For example, the code below creates a Rect object with a top left corner at (10, 20) that is 200 pixels wide and 300 pixels tall:
import pygame
spamRect = pygame.Rect(10, 20, 200, 300)
spamRect == (10, 20, 200, 300)
Rect object automatically calculates the coordinates for other features of the rectangle. For example, if you need to know the X coordinate of the right edge of the pygame.Rect
object we stored in the spamRect
variable, you can access the Rect object's right
attribute:
spamRect.right
Here is a list of all the attributes that pygame.Rect
objects provide:
| Attribute Name | Description |
|--------------------|------------------------------------------------------------------------|
| myRect.left | The int value of the X-coordinate of the left side of the rectangle |
| myRect.right | The int value of the X-coordinate of the right side of the rectangle |
| myRect.top | The int value of the Y-coordinate of the top side of the rectangle |
| myRect.bottom | The int value of the Y-coordinate of the bottom side of the rectangle |
| myRect.centerx | The int value of the X-coordinate of the center of the rectangle |
| myRect.centery | The int value of the Y-coordinate of the center of the rectangle |
| myRect.width | The int value of the width of the rectangle |
| myRect.height | The int value of the height of the rectangle |
| myRect.size | A tuple of two ints: (width, height) |
| myRect.topleft | A tuple of two ints: (left, top) |
| myRect.topright | A tuple of two ints: (right, top) |
| myRect.bottomleft | A tuple of two ints: (left, bottom) |
| myRect.bottomright | A tuple of two ints: (right, bottom) |
| myRect.midleft | A tuple of two ints: (left, center) |
| myRect.midright | A tuple of two ints: (right, center) |
| myRect.midtop | A tuple of two ints: (centerx, top) |
| myRect.midbottom | A tuple of two ints: (centerx, bottom) |
Pygame provides several different functions for drawing different shapes onto a surface object. These shapes such as rectangles, circles, ellipses, lines, or individual pixels are often called drawing primitives.
import pygame, sys
from pygame.locals import *
pygame.init()
# set up the window
surf = pygame.display.set_mode((500, 400), 0, 32)
pygame.display.set_caption('Drawing')
# set up the colors
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
# draw on the surface object
surf.fill(WHITE)
pygame.draw.polygon(surf, GREEN, ((146, 0), (291, 106), (236, 277), (56, 277), (0, 106)))
pygame.draw.line(surf, BLUE, (60, 60), (120, 60), 4)
pygame.draw.line(surf, BLUE, (120, 60), (60, 120))
pygame.draw.line(surf, BLUE, (60, 120), (120, 120), 4)
pygame.draw.circle(surf, BLUE, (300, 50), 20, 0)
pygame.draw.ellipse(surf, RED, (300, 250, 40, 80), 1)
pygame.draw.rect(surf, RED, (200, 150, 100, 50))
pixObj = pygame.PixelArray(surf)
pixObj[480][380] = BLACK
pixObj[482][382] = BLACK
pixObj[484][384] = BLACK
pixObj[486][386] = BLACK
pixObj[488][388] = BLACK
del pixObj
# game loop
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
pygame.display.update()
Output:
Here is a short description of each function:
fill()
method is a method of pygame.Surface
objects. It will completely fill in the entire Surface object with whatever color value you pass as for the color
parameter.start_point
and end_point
parameters.bounding_rectangle
parameter can be a pygame.Rect
object or a tuple of four integers. There isn't a single function you can call that will set a single pixel to a color (unless you call pygame.draw.line()
with the same start and endpoint). The Pygame library needs to run some code in the background before and after drawing to a Surface object. If it had to do this for every pixel you wanted to set, your program would run much slower.
Instead, you should create a pygame.PixelArray
object of a Surface object and then set individual pixels.
The PixelArray object that is returned from pygame.PixelArray()
can have individual pixels set by accessing them with two indexes. To tell Pygame that you are finished drawing individual pixels, delete the PixelArray object with a del
statement. Deleting the PixelArray object will unlock the Surface object so that you can once again draw images on it. If you forget to delete the PixelArray object, the next time you try to draw an image to the Surface, the program will raise an error.
After you are done calling the drawing functions to make the display Surface object look the way you want, you must call pygame.display.update()
to make the display Surface appear.
The one thing that you must remember is that pygame.display.update()
will only make the display Surface appear on the screen. If you want the images on other Surface objects to appear on the screen, you must copy them to the display Surface object with the blit()
method, which will be explained later.
Animated images are the result of drawing an image on the screen, then a split second later drawing a slightly different image.
Example:
import pygame, sys
from pygame.locals import *
pygame.init()
FPS = 30
fpsClock = pygame.time.Clock()
surf = pygame.display.set_mode((400, 300), 0, 32)
pygame.display.set_caption('Animation')
WHITE = (255, 255, 255)
catImg = pygame.image.load(image.png)
catx = 10
caty = 10
direction = 'right'
while True:
surf.fill(WHITE)
if direction == 'right':
catx += 5
if catx == 280:
direction = 'down'
elif direction == 'down'
catx += 5
if caty == 220:
direction = 'left'
elif direction == 'left'
catx -= 5
if catx == 10:
direction = 'up'
elif direction == 'up'
catx -= 5
if caty == 10:
direction = 'right'
surf.blit(catImg, (catx, caty))
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
pygame.display.update()
fpsClock.tick(FPS)
The frame rate or refresh rate is the number of pictures that the program draws per second, and it is measured in FPS (frames per second). A low frame rate in video games can make the game look choppy.
A pygame.time.Clock
object can help us make sure our program runs at a certain maximum FPS. A call to the tick()
method of a Clock object in the game loop can make sure the game runs at the same speed no matter how fast of a computer it runs on.
Pygame is able to load images onto Surface objects from PNG, JPG, GIF, and BMP image files. The pygame.image.load()
function call will return a Surface object from the display Surface object, so we must copy the image's Surface object to the display Surface object. Blitting is drawing the contents of one Surface onto another. It is done with the blit()
Surface object method.
Pygame provides some functions for fonts and creating text. The steps for making text appear on the screen:
pygame.font.Font
object:fontObj = pygame.font.Font('freesansbold.ttf', 32)
render()
method:GREEN = (0, 255, 0)
BLUE = (0, 0, 128)
textSurfaceObj = fontObj.render('Hello world!', True, GREEN, BLUE)
get_rect()
method:textRectObj = textSurfaceObj.get_rect()
This Rect object will have the width and height correctly set for the text that was rendered, but the top and left attributes will be zero.
Set the position of the Rect object by changing one of its attributes.
Blit the surface object with the text onto the Surface object returned by pygame.display.set_mode()
Call pygame.display.update()
to make the display Surface appear on the screen.
Anti-aliasing is a graphics technique for making text and shapes look less blocky by adding a bit of blur to their edges. To make Pygame's text use anti-aliasing, just pass True
for the second parameter of the render()
method. The pygame.draw.aaline()
and pygame.draw.aalines()
functions have the same parameters as pygame.draw.line()
and pygame.draw.lines()
, except they will draw anti-aliased lines instead of aliased lines.
You must create a pygame.mixer.Sound
object by calling the pygame.mixer.Sound()
constructor function. Pygame can load WAV, MP3, or OGG files. To play the sound, call the Sound object's play()
method. If you want to stop the Sound object from playing call the stop()
method.
Example:
soundObj = pygame.mixer.Sound('music.wav')
soundObj.play()
import time
time.sleep(1)
soundObj.stop()
Pygame can only load one music file to play in the background at a time. To load a background music file, call the pygame.mixer.music.load()
function. This file can be WAV, MP3, or MIDI format. To begin playing the loaded sound file as the background music, call the pygame.mixer.music.play(-1, 0.0)
function. The -1
argument makes the background music forever loop when it reaches the end of the sound file. The 0.0
argument means to start playing the sound file from the beginning. To stop playing the background music, call the pygame.mixer.music.stop()
function.
Example:
pygame.mixer.music.load('backgroundmusic.mp3')
pygame.mixer.music.play(-1, 0.0)
pygame.mixer.music.stop()
This article covered the basics of Python's Pygame library for game development, like images, animations, and sounds.
Nemanja Grubor
See other articles by Nemanja
Ground Floor, Verse Building, 18 Brunswick Place, London, N1 6DZ
108 E 16th Street, New York, NY 10003
Join over 111,000 others and get access to exclusive content, job opportunities and more!