Skip to content

Pygame

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

Terms

pygame-ce

pip install pygame-ce

pygame 메인테이너가 강압적이라 포크 따서 분할된듯? -> Pygame CE - Better & Faster - YouTube (누군가의 의견)

Free Game Tools

OpenGL 지원 관련

랜더링 파이프라인이 바뀌는듯함... 기존 pygame 의 drawing 관련 API 들이 작동하지 않더라... (정확히 확인 안됨) 관련 예제는 pyimgui 항목 참조.

PyOpenGL 그림 그리기

PyOpenGL 폰트 그리기

Generator

Show OpenCV Image

핵심 코드:

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

폰트 추가하기

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

전체화면 이슈 (픽셀레이트, 하드웨어 오류 등)

참고로 폰트의 경우 Anti-aliasing 효과 플래그가 있다. 픽셀 아트 느낌을 살리고 싶다면 효과 유무를 잘 선택하자.

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)

게임에 사용하기 좋은 잘 알려진 화면 해상도

Display resolution#게임에 사용하기 좋은 잘 알려진 화면 해상도 항목 참조.

pygame.sprite.Sprite 클래스 사용 방법

Python 으로 구름 이미지 생성하기 (Cloud images using the diamond-square algorithm)

자세한 내용은 해당 문서 참조.

이미지 또는 색상 블랜딩 하는 방법

이미지 회전 이슈

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) 및 광원 효과

물/바람/풀 (Water, Wind, Grass) 흔들림 효과

3,000+ Particles with Physics

Shaders in Pygame

연기 (스모크) 효과

불(Fire) 효과

옷(Cloth)이 흣날리는 느낌 VFX

스파크(Spark) VFX

아웃 라인 그리기

Sprite Stacking

2D 스프라이트를 쌓아서 3D처럼 보이게 만드는 기법입니다.

더스트 트레일 혀과 (뛸 때 발생하는 먼지 효과)

공기중의 먼지 흩날림 (파티클)

dust particles floating in the air ...

셀레스트의 윈드 파티클 (Celeste Wind Particle)

Background Parallax Scrolling

장면 트랜지션 (Scene Transitions)

SVG 로드

문자열에서 로드 (간단히):

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

문자열에서 로드 (긴 버전):

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

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)

긴 버전 예제:

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

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)

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 모드

SDL_VIDEODRIVER 환경변수를 dummy 또는 fbcon 으로 하면 되는듯?

FFmpeg 로 실시간 랜더링

ffmpeg-python#pygame으로 실시간 랜더링하기 항목 참조.

Troubleshooting

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

Ubuntu 20.04 이상에서 Wayland 로 실행된다면 다음과 같은 에러가 출력될 수 있다:

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

PyGame이 Wayland와 직접 인터페이스하는 대신 X11 호환 계층을 사용하여 Wayland 세션에서 실행되고 있음을 나타냅니다. 이는 성능과 호환성에 영향을 미칠 수 있습니다.

다음과 같이 SDL_VIDEO_X11_FORCE_EGL=1 환경변수 설정하면 된다:

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

또는 직접 wayland 드라이버를 사용하면 된다더라 <- 차 후 해결 방법 찾아보기

export SDL_VIDEODRIVER=wayland

See also

Favorite site

References