We're planting a tree for every job application! Click here to learn more

Game Development with Python

Nemanja Grubor

15 Jul 2021

•

10 min read

Game Development with Python
  • Python

Introduction

In this article, we will talk about game development basics in Python. We will review the Pygame library.

Pygame Library

Pygame library includes several modules with functions for drawing graphics, playing sounds, handling mouse input, etc.

GUI vs CLI

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.

Hello World with Pygame

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:

image1.JPG

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:

  • Handles events
  • Updates the game state
  • Draws the game state to the screen

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.

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.

The QUIT Event and pygame.quit() Function

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

Surface objects are objects that represent a rectangular 2D image. The Surface object returned by pygame.display.set_mode() is called the display Surface.

Colors

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)   |

Transparent Colors

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().

pygame.Color Objects

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.

Rect Objects

Pygame has two ways to represent rectangular areas. The first is a tuple of four integers:

  • The X coordinate of the top left corner
  • The Y coordinate of the top left corner
  • The width (in pixels) of the rectangle
  • The height of the rectangle

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)                                 |

Primitive Drawing Functions

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:

image2.JPG

Here is a short description of each function:

  • fill(color). The 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.
  • pygame.draw.polygon(surface, color, pointlist, width). This function draws a polygon with specified parameters
  • pygame.draw.line(surface, color, start_point, end_point, width). This function draws a line between the start_point and end_point parameters.
  • pygame.draw.circle(surface, color, center_point, radius, width). This function draws a circle.
  • pygame.draw.ellipse(surface, color, bounding_rectangle, width). This function draws an ellipse. In order to tell the function how large where to draw the ellipse, you must specify the bounding rectangle of the ellipse. A bounding rectangle is the smallest rectangle that can be drawn around a shape. The bounding_rectangle parameter can be a pygame.Rect object or a tuple of four integers.
  • pygame.draw.rect(surface, color, rectangle_tuple, width). This function draws a rectangle.

pygame.PixelArray Objects

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.

The pygame.display.update() Function

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.

Animation

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)

FPS and pygame.time.Clock Objects

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.

Drawing Images with pygame.image.load() and blit()

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.

Fonts

Pygame provides some functions for fonts and creating text. The steps for making text appear on the screen:

  • Create a pygame.font.Font object:
fontObj = pygame.font.Font('freesansbold.ttf', 32)
  • Create a Surface object with the text drawn on it by calling the Font object's render() method:
GREEN = (0, 255, 0)
BLUE = (0, 0, 128)
textSurfaceObj = fontObj.render('Hello world!', True, GREEN, BLUE)
  • Create a Rect object from the Surface object by calling the Surface object's 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

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.

Sounds

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()

Conclusion

This article covered the basics of Python's Pygame library for game development, like images, animations, and sounds.

Did you like this article?

Nemanja Grubor

See other articles by Nemanja

Related jobs

See all

Title

The company

  • Remote

Title

The company

  • Remote

Title

The company

  • Remote

Title

The company

  • Remote

Related articles

JavaScript Functional Style Made Simple

JavaScript Functional Style Made Simple

Daniel Boros

•

12 Sep 2021

JavaScript Functional Style Made Simple

JavaScript Functional Style Made Simple

Daniel Boros

•

12 Sep 2021

WorksHub

CareersCompaniesSitemapFunctional WorksBlockchain WorksJavaScript WorksAI WorksGolang WorksJava WorksPython WorksRemote Works
hello@works-hub.com

Ground Floor, Verse Building, 18 Brunswick Place, London, N1 6DZ

108 E 16th Street, New York, NY 10003

Subscribe to our newsletter

Join over 111,000 others and get access to exclusive content, job opportunities and more!

© 2024 WorksHub

Privacy PolicyDeveloped by WorksHub