pygame 치트시트
마지막 업데이트
설정과 게임 루프
모든 pygame 프로그램은 창을 연 다음, 플레이어가 종료할 때까지 하나의 루프를 반복합니다.
| 작업 | 코드 |
|---|---|
| pygame-ce 설치 | python3 -m pip install pygame-ce |
| pygame 불러오기와 초기화 | import pygame
pygame.init() |
| 창 열기 | screen = pygame.display.set_mode((640, 480)) |
| 창 제목 설정 | pygame.display.set_caption("My Game") |
| Clock 만들기 | clock = pygame.time.Clock() |
| 게임 루프 | running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
screen.fill("black")
pygame.display.flip()
clock.tick(60) |
| 루프가 끝난 뒤 종료 | pygame.quit() |
화면
화면은 Surface이며, flip하기 전에는 아무것도 보이지 않습니다.
| 작업 | 코드 |
|---|---|
| 완성된 프레임 표시 | pygame.display.flip() |
| 일부 영역만 갱신 | pygame.display.update([rect1, rect2]) |
| 화면 지우기 | screen.fill((30, 30, 46)) |
| 창 크기 | screen.get_size(), screen.get_width() |
| 화면을 Rect로 얻기 | screen.get_rect() |
| 크기를 바꿀 수 있는 창 | pygame.display.set_mode((640, 480), pygame.RESIZABLE) |
| 데스크톱 크기로 전체 화면 | pygame.display.set_mode((0, 0), pygame.FULLSCREEN) |
색과 그리기
pygame.draw 함수는 Surface, 색, 위치를 받습니다. width=0이면 안을 채웁니다.
| 작업 | 코드 |
|---|---|
| RGB 색 | (255, 140, 0) |
| 이름이나 16진수로 지정한 색 | "tomato", "#ff8c00", pygame.Color("gold") |
| 사각형 | pygame.draw.rect(screen, "red", (x, y, w, h)) |
| 테두리와 둥근 모서리 | pygame.draw.rect(screen, "red", rect, width=2, border_radius=8) |
| 원 (중심 기준) | pygame.draw.circle(screen, "blue", (cx, cy), radius) |
| 선 | pygame.draw.line(screen, "white", (x1, y1), (x2, y2), 3) |
| 다각형 | pygame.draw.polygon(screen, "green", [(0, 0), (40, 0), (20, 30)]) |
| 상자 안의 타원 | pygame.draw.ellipse(screen, "purple", (x, y, w, h)) |
Rect
Rect는 위치와 크기를 정수로 저장합니다.
| 작업 | 코드 |
|---|---|
| Rect 만들기 | player = pygame.Rect(x, y, width, height) |
| 원하는 기준점으로 위치 지정 | player.center = (320, 240), player.bottom = 400 |
| 변과 모서리 | left, right, top, bottom, topleft, midbottom |
| 제자리에서 이동 | player.move_ip(dx, dy) |
| 이동한 복사본 | moved = player.move(dx, dy) |
| 화면 안에 가두기 | player.clamp_ip(screen.get_rect()) |
| 중심을 기준으로 키우기 | bigger = player.inflate(20, 20) |
| 실수 좌표 (pygame-ce) | pygame.FRect(10.5, 20.25, 40, 40) |
이미지, Surface, blit
이미지는 루프 전에 한 번만 불러오고, 매 프레임 blit합니다.
| 작업 | 코드 |
|---|---|
| 투명도가 있는 이미지 불러오기 | img = pygame.image.load("player.png").convert_alpha() |
| 투명도가 없는 이미지 불러오기 | bg = pygame.image.load("sky.png").convert() |
| 이미지 그리기 | screen.blit(img, (x, y)) |
| 가운데에 그리기 | screen.blit(img, img.get_rect(center=(320, 240))) |
| 빈 Surface 만들기 | panel = pygame.Surface((200, 100)) |
| 투명한 Surface | layer = pygame.Surface((200, 100), pygame.SRCALPHA) |
| Surface 전체를 반투명하게 | img.set_alpha(128) |
| 스프라이트 시트에서 한 프레임 잘라내기 | frame = sheet.subsurface((0, 0, 32, 32)) |
| 스크린샷 저장 | pygame.image.save(screen, "shot.png") |
변환
각 함수는 새 Surface를 돌려줍니다. 마지막 결과가 아니라 원본을 변환하세요.
| 작업 | 코드 |
|---|---|
| 크기 바꾸기 | pygame.transform.scale(img, (64, 64)) |
| 배율로 크기 조절 | pygame.transform.scale_by(img, 2) |
| 부드럽게 크기 바꾸기 | pygame.transform.smoothscale(img, (64, 64)) |
| 회전 (반시계 방향, 도 단위) | pygame.transform.rotate(img, 45) |
| 중심을 기준으로 회전 | rotated = pygame.transform.rotate(original, angle)
rect = rotated.get_rect(center=rect.center) |
| 좌우 반전 | pygame.transform.flip(img, True, False) |
이벤트와 키보드
한 번 누르는 입력은 이벤트로, 누르고 있는 키는 get_pressed()로 처리합니다.
| 작업 | 코드 |
|---|---|
| 이번 프레임의 이벤트 읽기 | for event in pygame.event.get(): |
| 창을 닫음 | event.type == pygame.QUIT |
| 키를 누름 | event.type == pygame.KEYDOWN and event.key == pygame.K_SPACE |
| 키를 뗌 | event.type == pygame.KEYUP |
| 입력한 문자 | event.unicode |
| 지금 누르고 있는 키 | keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
x -= 5 |
| 두 키로 방향 구하기 | dx = keys[pygame.K_RIGHT] - keys[pygame.K_LEFT] |
| 이번 프레임에 누른 키 (pygame-ce) | pygame.key.get_just_pressed()[pygame.K_SPACE] |
| 키 상수 | K_a...K_z, K_0...K_9, K_UP, K_RETURN, K_ESCAPE, K_LSHIFT |
| 키 이름 | pygame.key.name(event.key) |
| 사용자 정의 이벤트 | HIT = pygame.event.custom_type()
pygame.event.post(pygame.event.Event(HIT)) |
마우스
버튼: 1은 왼쪽, 2는 가운데, 3은 오른쪽.
| 작업 | 코드 |
|---|---|
| 버튼을 누름 | event.type == pygame.MOUSEBUTTONDOWN and event.button == 1 |
| 누른 위치 | event.pos |
| 현재 포인터 위치 | x, y = pygame.mouse.get_pos() |
| 지금 누르고 있는 버튼 | left, middle, right = pygame.mouse.get_pressed() |
| 마우스가 움직임 | event.type == pygame.MOUSEMOTION, event.rel |
| 휠을 굴림 | event.type == pygame.MOUSEWHEEL, event.y |
| 버튼 안을 클릭함 | button_rect.collidepoint(event.pos) |
| 포인터 숨기기 | pygame.mouse.set_visible(False) |
스프라이트와 그룹
스프라이트는 image와 rect를 가지고, 그룹은 여러 스프라이트를 한꺼번에 업데이트하고 그립니다.
| 작업 | 코드 |
|---|---|
| 스프라이트 클래스 | class Coin(pygame.sprite.Sprite):
def __init__(self, pos):
super().__init__()
self.image = coin_img
self.rect = self.image.get_rect(center=pos) |
| 그룹 만들기 | coins = pygame.sprite.Group() |
| 그룹에 추가 | coins.add(Coin((100, 50))) |
| 모든 스프라이트 업데이트 | coins.update() |
| 모든 스프라이트 그리기 | coins.draw(screen) |
| 모든 그룹에서 스프라이트 제거 | coin.kill() |
| 스프라이트 하나만 담는 그룹 | player = pygame.sprite.GroupSingle(Player()) |
충돌
Rect는 겹칠 때 충돌합니다. 변이 닿기만 한 것은 충돌로 치지 않습니다.
| 작업 | 코드 |
|---|---|
| 두 사각형 | a.colliderect(b) |
| 점이 안에 있는지 | rect.collidepoint(x, y) |
| 여러 개 중 첫 번째 | rect.collidelist(walls) # index or -1 |
| 스프라이트와 그룹 | hits = pygame.sprite.spritecollide(player, coins, True) |
| 하나라도 부딪혔는지 | pygame.sprite.spritecollideany(player, enemies) |
| 그룹과 그룹 | pygame.sprite.groupcollide(bullets, enemies, True, True) |
| 픽셀 단위 충돌 | pygame.sprite.spritecollide(a, group, False, pygame.sprite.collide_mask) |
| 원 | pygame.Vector2(a).distance_to(b) < r1 + r2 |
텍스트와 폰트
텍스트를 Surface로 렌더링한 다음 blit합니다.
| 작업 | 코드 |
|---|---|
| 기본 폰트 | font = pygame.font.Font(None, 36) |
| 시스템 폰트 | font = pygame.font.SysFont("arial", 24) |
| 폰트 파일 | font = pygame.font.Font("pixel.ttf", 32) |
| 텍스트 렌더링 | text = font.render("Score: 10", True, "white") |
| 가운데에 그리기 | screen.blit(text, text.get_rect(center=(320, 40))) |
| 긴 텍스트 줄바꿈 (pygame-ce) | font.render(story, True, "white", None, 400) |
| 렌더링하지 않고 크기 구하기 | font.size("Hello") |
| 설치된 폰트 | pygame.font.get_fonts() |
사운드와 음악
사운드는 한 번만 불러옵니다. 음악은 파일에서 한 곡을 스트리밍합니다.
| 작업 | 코드 |
|---|---|
| 사운드 불러오기 | jump = pygame.mixer.Sound("jump.ogg") |
| 재생하기 | jump.play() |
| 사운드 볼륨 | jump.set_volume(0.5) |
| 음악 불러오기 | pygame.mixer.music.load("theme.ogg") |
| 음악 무한 반복 | pygame.mixer.music.play(-1) |
| 일시 정지와 다시 재생 | pygame.mixer.music.pause(), pygame.mixer.music.unpause() |
| 음악 정지 | pygame.mixer.music.stop() |
시간과 타이머
틱 단위는 밀리초입니다.
| 작업 | 코드 |
|---|---|
| 프레임 속도 제한 | clock.tick(60) |
| 초 단위 델타 타임 | dt = clock.tick(60) / 1000 |
| 현재 프레임 속도 | clock.get_fps() |
| init 이후 지난 밀리초 | pygame.time.get_ticks() |
| 반복 타이머 이벤트 | SPAWN = pygame.event.custom_type()
pygame.time.set_timer(SPAWN, 1000) |
| 한 번만 실행되는 타이머 | pygame.time.set_timer(SPAWN, 2000, loops=1) |
| 타이머 멈추기 | pygame.time.set_timer(SPAWN, 0) |
Vector2
위치와 속도를 실수로 다룹니다.
| 작업 | 코드 |
|---|---|
| 벡터 만들기 | pos = pygame.Vector2(100, 200) |
| 속도만큼 이동 | pos += velocity * dt |
| 길이 | velocity.length() |
| 대각선에서도 같은 속도 | if direction.length() > 0:
direction = direction.normalize() |
| 두 점 사이 거리 | pos.distance_to(target) |
| 회전 | velocity.rotate(90) |
| 목표 지점으로 한 걸음 이동 (pygame-ce) | pos.move_towards_ip(target, 5) |
Python으로 2D 게임을 만들 때 자주 쓰는 pygame 코드를 작업별로 묶었습니다. 게임 루프, 화면, 색과 그리기, Rect, 이미지와 blit, 크기 조절과 회전, 키보드와 마우스 입력, 스프라이트와 그룹, 충돌, 텍스트, 사운드, 타이머, Vector2를 다룹니다. 각 행에는 바로 붙여 넣을 수 있는 짧은 코드와 그 코드가 하는 일이 나란히 있습니다.
여기 있는 코드는 모두 pygame의 커뮤니티 에디션인 pygame-ce 2.5 기준이며, 여전히 import pygame으로 불러옵니다. pygame-ce 표시가 있는 행은 pygame-ce에 추가된 기능을 쓰고, 나머지 행은 원래 pygame에서도 동작합니다. 어떤 코드든 pygame 플레이그라운드에서 실행해 볼 수 있습니다. 설치 없이 브라우저에서 pygame이 실행됩니다. Python 자체가 처음이라면 Python 치트시트부터 시작하세요.
pygame 치트시트 자주 묻는 질문
이 pygame 치트시트는 무료인가요?
네. 회원가입 없이 무료입니다. 북마크하거나 브라우저에서 PDF로 인쇄해 두고, 스프라이트 그룹, 사운드, 충돌 검사의 정확한 호출이 필요할 때마다 다시 찾아보세요.
이 치트시트는 pygame과 pygame-ce 모두에서 쓸 수 있나요?
import pygame으로 불러오고 API가 거의 전부 같습니다. pygame-ce 표시가 있는 행(FRect, scale_by, get_just_pressed, 텍스트 줄바꿈, move_towards_ip)은 pygame-ce가 필요하고, 나머지는 어느 쪽에서도 동작합니다.pygame 창이 응답하지 않는 이유는 무엇인가요?
pygame.event.get()을 한 번 호출하고, 각 프레임은 pygame.display.flip()과 clock.tick(60)으로 끝내세요.입력에는 이벤트와 key.get_pressed() 중 무엇을 써야 하나요?
KEYDOWN 이벤트를 쓰세요. 걷기처럼 키를 누르고 있는 동안 계속되는 동작에는 pygame.key.get_pressed()를 쓰세요.