Skip to content
Search

Pygame

lastmod 2026-03-27created 2020-05-0784 edits

Pygame is a cross-platform set of Python modules designed for writing video games. It includes computer graphics and sound libraries designed to be used with the Python programming language. It is built over the Simple DirectMedia Layer (SDL) library, with the intention of allowing real-time computer game development without the low-level mechanics of the C programming language and its derivatives. This is based on the assumption that the most expensive functions inside games (mainly the graphics part) can be abstracted from the game logic, making it possible to use a high-level programming language, such as Python, to structure the game.

Categories

Modules

  • pygame._sdl2.controller - pygame module to work with controllers
  • pygame._sdl2.touch - pygame module to work with touch input
  • pygame._sdl2.video - Experimental pygame module for porting new SDL video systems
  • pygame.camera - pygame module for camera use
  • pygame.cursors - pygame module for cursor resources
  • pygame.display - pygame module to control the display window and screen
  • pygame.draw - pygame module for drawing shapes
  • pygame.event - pygame module for interacting with events and queues
  • pygame.examples - module of example programs
  • pygame.font - pygame module for loading and rendering fonts
  • pygame.freetype - Enhanced pygame module for loading and rendering computer fonts
  • pygame.geometry - pygame geometry module
  • pygame.gfxdraw - pygame module for drawing shapes
  • pygame.image - pygame module for loading and saving images
  • pygame.joystick - Pygame module for interacting with joysticks, gamepads, and trackballs.
  • pygame.key - pygame module to work with the keyboard
  • pygame.locals - pygame constants
  • pygame.mask - pygame module for image masks.
  • pygame.math - pygame module for vector classes
  • pygame.midi - pygame module for interacting with midi input and output.
  • pygame.mixer - pygame module for loading and playing sounds
  • pygame.mixer.music - pygame module for controlling streamed audio
  • pygame.mouse - pygame module to work with the mouse
  • pygame.pixelcopy - pygame module for general pixel array copying
  • pygame.scrap - pygame module for clipboard support.
  • pygame.sndarray - pygame module for accessing sound sample data
  • pygame.sprite - pygame module with basic game object classes
  • pygame.surfarray - pygame module for accessing surface pixel data using array interfaces
  • pygame.system - pygame module to provide additional context about the system
  • pygame.tests - Pygame unit test suite package
  • pygame.time - pygame module for monitoring time
  • pygame.transform - pygame module to transform surfaces
  • pygame.version - small module containing version information

Libraries

GUI Libraries

WebAssembly

Packaging

Examples

Terms

pygame-ce

pip install pygame-ce

Seems it was forked off because the pygame maintainer was overbearing? -> Pygame CE - Better & Faster - YouTube (someone's opinion)

Free Game Tools

OpenGL support

The rendering pipeline seems to change... the existing pygame drawing APIs didn't work... (not confirmed exactly) See pyimgui for related examples.

Drawing images with PyOpenGL

Drawing fonts with PyOpenGL

Generator

Show OpenCV Image

Key code:

pygame.image.frombuffer(image.tostring(), image.shape[1::-1], "BGR")

Minimal example:

import pygame
import cv2

video = cv2.VideoCapture("video.mp4")
success, video_image = video.read()
fps = video.get(cv2.CAP_PROP_FPS)

window = pygame.display.set_mode(video_image.shape[1::-1])
clock = pygame.time.Clock()

run = success
while run:
    clock.tick(fps)
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False

    success, video_image = video.read()
    if success:
        video_surf = pygame.image.frombuffer(
            video_image.tobytes(), video_image.shape[1::-1], "BGR")
    else:
        run = False
    window.blit(video_surf, (0, 0))
    pygame.display.flip()

pygame.quit()
exit()

Sample program

import sys, pygame
pygame.init()

size = width, height = 320, 240
speed = [2, 2]
black = 0, 0, 0

screen = pygame.display.set_mode(size)

ball = pygame.image.load("ball.gif")
ballrect = ball.get_rect()

while 1:
    for event in pygame.event.get():
        if event.type == pygame.QUIT: sys.exit()

    ballrect = ballrect.move(speed)
    if ballrect.left < 0 or ballrect.right > width:
        speed[0] = -speed[0]
    if ballrect.top < 0 or ballrect.bottom > height:
        speed[1] = -speed[1]

    screen.fill(black)
    screen.blit(ball, ballrect)
    pygame.display.flip()

Adding fonts

import pygame, sys
from pygame.locals import *

pygame.init()
DISPLAYSURF = pygame.display.set_mode((400,300))
pygame.display.set_caption('Hello World!')

WHITE = (255, 255, 255)
GREEN = (0, 255, 0)
BLUE = (0, 0, 128)
BLACK = (0, 0, 0)

fontObj = pygame.font.Font('font/nanum.ttf', 32)
textSurfaceObj = fontObj.render('Hello world!', True, BLACK, WHITE)
textRectObj = textSurfaceObj.get_rect()
textRectObj.center = (100, 16)

while True: # main game loop
    DISPLAYSURF.fill(WHITE)
    DISPLAYSURF.blit(textSurfaceObj, textRectObj)
    for event in pygame.event.get():
        if event.type == QUIT:
            pygame.quit()
            sys.exit()
    pygame.display.update()

Fullscreen issues (pixelation, hardware errors, etc.)

Note that fonts have an Anti-aliasing flag. If you want to keep a pixel-art look, choose carefully whether to turn it on.

Handling Fullscreen Toggle

...
# Game loop
run = True
fullscreen = False
while run:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False
        # Toggle fullscreen when F11 is pressed
        elif event.type == pygame.KEYDOWN:
            if event.key == pygame.K_F11:
                fullscreen = not fullscreen
                if fullscreen:
                    win = pygame.display.set_mode((0, 0), pygame.FULLSCREEN)
                else:
                    win = pygame.display.set_mode((800, 600))
pygame.quit()

Exiting From Fullscreen

# Game loop
run = True
while run:
  for event in pygame.event.get():
        if event.type == pygame.QUIT or (event.type == pygame.KEYDOWN and event.key == pygame.K_F11):
            run = False
            # Switch back to windowed mode before exiting
            pygame.display.set_mode((800, 600))

Adjusting Screen Resolution

# Get screen size
screen = pygame.display.get_surface()
width, height = screen.get_size()
# Game loop
run = True
while run:
    # Switch fullscreen/resolution when F11 is pressed
    if fullscreen:
        win = pygame.display.set_mode((width, height), pygame.FULLSCREEN)
    else:
        win = pygame.display.set_mode((800, 600))

Handling Multiple Sizable Game Elements

from pygame import transform
def load_image(filename, width, height):
    # Load image
    img= pygame.image.load(filename)

    # Scale image
    scaled_img = transform.scale(img, (width, height))

    return scaled_img
# Load and scale images
background = load_image('background.png', width, height)
player = load_image('player.png', 100, 100)
# Game loop
run = True
while run:
    ...
    # Draw images
    win.blit(background, (0, 0))
    win.blit(player, (width//2, height//2))

Disabling antialiasing on fullscreen mode

game_resolution = (800, 600)
display_resolution = (8000, 6000) # Or use a function to get the real screen res
stretch_to_fit_resolution = (display_resultion[0]^2/game_resolution[0], display_resultion[1]^2/game_resolution[1])
# ...
screen = pygame.display.set_mode(display_resolution, pygame.FULLSCREEN)

Then, inside the game-loop:

pygame.transform.scale(screen, stretch_to_fit_resultion, screen)

Well-known screen resolutions suitable for games

See Display resolution#Well-known screen resolutions suitable for games.

How to use the pygame.sprite.Sprite class

Generating cloud images with Python (Cloud images using the diamond-square algorithm)

See the relevant page for details.

How to blend images or colors

Image rotation issues

import pygame

pygame.init()
screen = pygame.display.set_mode((300, 300))
clock = pygame.time.Clock()

def blitRotate(surf, image, pos, originPos, angle):

    # offset from pivot to center
    image_rect = image.get_rect(topleft = (pos[0] - originPos[0], pos[1]-originPos[1]))
    offset_center_to_pivot = pygame.math.Vector2(pos) - image_rect.center

    # roatated offset from pivot to center
    rotated_offset = offset_center_to_pivot.rotate(-angle)

    # roatetd image center
    rotated_image_center = (pos[0] - rotated_offset.x, pos[1] - rotated_offset.y)

    # get a rotated image
    rotated_image = pygame.transform.rotate(image, angle)
    rotated_image_rect = rotated_image.get_rect(center = rotated_image_center)

    # rotate and blit the image
    surf.blit(rotated_image, rotated_image_rect)

    # draw rectangle around the image
    pygame.draw.rect(surf, (255, 0, 0), (*rotated_image_rect.topleft, *rotated_image.get_size()),2)

def blitRotate2(surf, image, topleft, angle):

    rotated_image = pygame.transform.rotate(image, angle)
    new_rect = rotated_image.get_rect(center = image.get_rect(topleft = topleft).center)

    surf.blit(rotated_image, new_rect.topleft)
    pygame.draw.rect(surf, (255, 0, 0), new_rect, 2)

try:
    image = pygame.image.load('AirPlaneFront.png')
except:
    text = pygame.font.SysFont('Times New Roman', 50).render('image', False, (255, 255, 0))
    image = pygame.Surface((text.get_width()+1, text.get_height()+1))
    pygame.draw.rect(image, (0, 0, 255), (1, 1, *text.get_size()))
    image.blit(text, (1, 1))
w, h = image.get_size()

angle = 0
done = False
while not done:
    clock.tick(60)
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            done = True

    pos = (screen.get_width()/2, screen.get_height()/2)

    screen.fill(0)
    blitRotate(screen, image, pos, (w/2, h/2), angle)
    #blitRotate2(screen, image, pos, angle)
    angle += 1

    pygame.draw.line(screen, (0, 255, 0), (pos[0]-20, pos[1]), (pos[0]+20, pos[1]), 3)
    pygame.draw.line(screen, (0, 255, 0), (pos[0], pos[1]-20), (pos[0], pos[1]+20), 3)
    pygame.draw.circle(screen, (0, 255, 0), pos, 7, 0)

    pygame.display.flip()

pygame.quit()
exit()

Particles

Screen Shake

Lighting effects and light source effects

Water/wind/grass (Water, Wind, Grass) sway effects

3,000+ Particles with Physics

Shaders in Pygame

Smoke effects

Fire effects

Fluttering cloth VFX

Spark VFX

Drawing outlines

Sprite Stacking

A technique that stacks 2D sprites to make them look 3D.

Dust trail effect (dust kicked up when running)

Dust floating in the air (particles)

dust particles floating in the air ...

Celeste's wind particles (Celeste Wind Particle)

Background Parallax Scrolling

Scene Transitions

Loading SVG

Loading from a string (short):

svg_string = '<svg height="100" width="500">...</svg>'
pygame_surface = pygame.image.load(io.BytesIO(svg_string.encode()))

Loading from a string (long version):

import pygame
import io

pygame.init()
window = pygame.display.set_mode((500, 200))
clock = pygame.time.Clock()

svg_string = '<svg height="100" width="500"><ellipse cx="240" cy="50" rx="220" ry="30" style="fill:yellow" /><ellipse cx="220" cy="50" rx="190" ry="20" style="fill:white" /></svg>'
pygame_surface = pygame.image.load(io.BytesIO(svg_string.encode()))

run = True
while run:
    clock.tick(60)
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False

    window.fill((255, 255, 255))
    window.blit(pygame_surface, pygame_surface.get_rect(center = window.get_rect().center))
    pygame.display.flip()

pygame.quit()
exit()

Using svglib

from svglib.svglib import svg2rlg
import io

def load_svg(svg_string):
    svg_io = io.StringIO(svg_string)
    drawing = svg2rlg(svg_io)
    str = drawing.asString("png")
    byte_io = io.BytesIO(str)
    return pygame.image.load(byte_io)

Long version example:

from svglib.svglib import svg2rlg
import pygame
import io

def load_svg_svglib(svg_string):
    svg_io = io.StringIO(svg_string)
    drawing = svg2rlg(svg_io)
    str = drawing.asString("png")
    byte_io = io.BytesIO(str)
    svg_surf = pygame.image.load(byte_io)
    return svg_surf

def display_svg_figure(screen, svg_string):
    surf = load_svg_svglib(svg_string)
    screen.blit(surf, (0, 0))

background_colour = (255, 255, 255)
(width, height) = (900, 900)

screen = pygame.display.set_mode((width, height))
pygame.display.set_caption('Display SVG')
screen.fill(background_colour)

svg_string='<svg height="100" width="500"><ellipse cx="240" cy="50" rx="220" ry="30" style="fill:yellow" /><ellipse cx="220" cy="50" rx="190" ry="20" style="fill:white" /></svg>'
display_svg_figure(screen, svg_string)

running = True
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False

    pygame.display.flip()

Using CairoSVG

import cairosvg
import io

def load_svg(filename):
    new_bites = cairosvg.svg2png(url = filename)
    byte_io = io.BytesIO(new_bites)
    return pygame.image.load(byte_io)

Using pynanosvg

Pygame Subset for Android

The Pygame Subset for Android is a port of a subset of Pygame functionality to the Android platform. The goal of the project is to allow the creation of Android-specific games, and to ease the porting of games from PC-like platforms to Android.

Headless mode

Setting the SDL_VIDEODRIVER environment variable to dummy or fbcon seems to do it?

Real-time rendering with FFmpeg

See ffmpeg-python#Real-time rendering with pygame.

Auto-detecting and setting SDL environment variables

See Simple DirectMedia Layer#Auto-detecting and setting SDL environment variables for details.

Troubleshooting

OpenGL.error.Error: Attempt to retrieve context when no valid context

When running under Wayland on Ubuntu 20.04 or later, the following error may be printed:

pygame-ce 2.4.1 (SDL 2.28.5, Python 3.11.4)
/home/your/Project/ddrm/test.py:13: Warning: PyGame seems to be running through X11 on top of wayland, instead of wayland directly
...
OpenGL.error.Error: Attempt to retrieve context when no valid context

This indicates that PyGame is running in a Wayland session through an X11 compatibility layer instead of interfacing with Wayland directly. This can affect performance and compatibility.

Set the SDL_VIDEO_X11_FORCE_EGL=1 environment variable as follows:

import os
os.environ["SDL_VIDEO_X11_FORCE_EGL"] = "1"

Or reportedly you can use the wayland driver directly <- look into this solution later

export SDL_VIDEODRIVER=wayland

See also

Favorite site

References

author Zer0 sitemap