안녕하세요? 초코쌤입니다.
작년(2024년) 11월호에 잠깐 PyGame으로 공룡게임 만들기에 대해서 소개해드렸는데요~
PyGame으로 게임 만들기 시리즈를 이어 가보려고 합니다 ㅎㅎ
이번에는 스베랑카(SUBERUNKER)라는 게임을 만들어보려고 하는데요.
흔히, 똥피하기 게임이라고 하면 모두 한 번쯤은 해보셨을 게임입니다 ㅎㅎ
이번호에서 만들 것은 아래와 같습니다 
PyGame 세팅작업은 24년 11월호를 참고해주세요 
큰 틀 잡기
1.
초깃값 세팅
import pygame #Pygame 기능 쓰기 위함
WIDTH, HEIGHT = 400, 600 # 창 크기
WHITE = (255, 255, 255)
BLACK = (0,0,0)
Python
복사
•
먼저 위와 같이 코드를 작성합니다.
•
먼저, import pygame을 써주시고, 화면을 세로로 긴 형태로 출력하기 위해 400 x 600 정도로 지정합니다.
•
하얀색 배경을 쓰기 위해 RGB값을 255, 255, 255로 지정합니다.
2.
Game 클래스 설계
•
Game 클래스란 게임 자체를 관리하는 클래스라고 생각하면 됩니다.
•
이렇게 클래스를 활용하여 Game 클래스 하나만으로도 게임의 흐름(입력 → 갱신 → 그리기)을 한눈에 볼 수 있게 하겠습니다.
import pygame #Pygame 기능 쓰기 위함
import sys #sys.exit()를 사용하기 위함
WIDTH, HEIGHT = 400, 600 # 창 크기
FPS = 60 # 초당 60프레임
WHITE = (255, 255, 255)
BLACK = (0,0,0)
class Game:
def __init__(self):
pygame.init() # Pygame 초기화
#위에서 설정한 변수로 게임 스크린 크기 설정
self.screen = pygame.display.set_mode((WIDTH, HEIGHT))
# 창 제목 설정
pygame.display.set_caption("Suberunker Game")
# FPS를 제어해주는 '시계' 생성
self.clock = pygame.time.Clock()
#run이라는 함수를 계속 돌릴지 여부
self.running = True
def run(self):
while self.running: # running이 True인 동안 계속 반복
self.clock.tick(FPS) # 프레임 속도 제어
for e in pygame.event.get(): # 마우스/키보드 등 이벤트를 꺼낸다.
if e.type == pygame.QUIT: # 꺼낸 이벤트가 종료라면 running을
self.running = False # false로 만들어서 게임 종료.
self.screen.fill(WHITE) # 배경을 하얀색으로 칠하고
pygame.display.flip() # 화면 업데이트
pygame.quit() #Pygame 닫기
sys.exit() #파이썬 프로그램 완전 종료
game = Game()
game.run()
Python
복사
•
위와 같이 코드를 작성하면 아래와 같은 하얀색 실행 화면을 확인할 수 있습니다.
•
FPS란 Frame Per Second로 ‘초당 프레임이 몇이냐?’ 를 의미합니다. 60fps는 초당 60장의 그림을 빠르게 넘겨 보여준다고 생각하면 됩니다. 마치 플립 북 애니메이션이라고 생각하시면 이해가 빠르실 겁니다.
•
import sys를 한 이유는 IDLE에서 개발하고 있기 때문인데, 파이썬 프로그램을 완전히 종료(sys.exit())하기 위함입니다. visual studio code 등의 환경에서는 신경 안 써도 됩니다.
플레이어를 움직일 수 있게 하기
1.
플레이어 클래스 설계하기
•
플레이어가 필요한 것을 먼저 생각해 보겠습니다.
•
먼저 플레이어는 사각형으로 그릴 것이고, 색깔과 속도라는 특성을 주겠습니다.
import pygame #Pygame 기능 쓰기 위함
import sys #sys.exit()를 사용하기 위함
WIDTH, HEIGHT = 400, 600 # 창 크기
FPS = 60 # 초당 60프레임
WHITE = (255, 255, 255)
BLACK = (0,0,0)
class Player:
def __init__(self, x, y, w=40, h=40, speed=5, color=BLACK):
self.rect = pygame.Rect(x, y, w, h) # 위치/크기
self.speed = speed # 한 프레임당 이동 픽셀
self.color = color
Python
복사
•
이번엔 키가 눌렸을 때 움직일 수 있게 하고, 그리는 함수를 추가하겠습니다.
import pygame #Pygame 기능 쓰기 위함
import sys #sys.exit()를 사용하기 위함
WIDTH, HEIGHT = 400, 600 # 창 크기
FPS = 60 # 초당 60프레임
WHITE = (255, 255, 255)
BLACK = (0,0,0)
class Player:
def __init__(self, x, y, w, h, speed, color):
self.rect = pygame.Rect(x, y, w, h) # 위치/크기
self.speed = speed # 한 프레임당 이동 픽셀
self.color = color
def handle_input(self):
# 현재 눌려 있는 키 상태를 한 번에 가져옵니다.
keys = pygame.key.get_pressed()
# ← 방향키가 눌렸으면 x값을 감소시켜서 위치를 왼쪽으로 이동
if keys[pygame.K_LEFT]:
self.rect.x -= self.speed
# → 방향키가 눌렸으면 x값을 증가시켜서 위치를 오른쪽으로 이동
if keys[pygame.K_RIGHT]:
self.rect.x += self.speed
def draw(self, screen):
# 플레이어(검정 사각형) 그리기
pygame.draw.rect(screen, self.color, self.rect)
Python
복사
PyGame에서는 좌표계를 위 그림과 같이 쓰기 때문에 왼쪽으로 이동하려면 빼고 오른쪽으로 이동하려면 더해야 하는 것입니다.
•
위와 코드를 작성했다면 Game 클래스에 아래와 같이 추가해 봅시다.
class Game:
def __init__(self):
pygame.init() # Pygame 초기화
#위에서 설정한 변수로 게임 스크린 크기 설정
self.screen = pygame.display.set_mode((WIDTH, HEIGHT))
# 창 제목 설정
pygame.display.set_caption("Suberunker Game")
# FPS를 제어해주는 '시계' 생성
self.clock = pygame.time.Clock()
#run이라는 함수를 계속 돌릴지 여부
self.running = True
# 플레이어 화면 아래 중앙 배치
px = WIDTH//2 - 20; py = HEIGHT - 60
self.player = Player(px, py, 40, 40, 5, BLACK)
def run(self):
while self.running: # running이 True인 동안 계속 반복
self.clock.tick(FPS) # 프레임 속도 제어
for e in pygame.event.get(): # 마우스/키보드 등 이벤트를 꺼낸다.
if e.type == pygame.QUIT: # 꺼낸 이벤트가 종료라면 running을
self.running = False # false로 만들어서 게임 종료.
self.player.handle_input() # 입력처리
self.screen.fill(WHITE) # 배경을 하얀색으로 칠하고
self.player.draw(self.screen) # 플레이어 그리기
pygame.display.flip() # 화면 업데이트
pygame.quit() #Pygame 닫기
sys.exit() #파이썬 프로그램 완전 종료
Python
복사
⇒ 그럼 이렇게 플레이어가 나오고 좌우로 움직여집니다 ㅎㅎ
여기서 speed 값을 바꾸면 누를 때마다 이동 감도가 확 달라지는 것을 느낄 수 있을 겁니다.
떨어지는 도형 만들기
•
갈색을 추가하고, 떨어질 도형의 크기를 지정하겠습니다.
import pygame #Pygame 기능 쓰기 위함
import sys #sys.exit()를 사용하기 위함
WIDTH, HEIGHT = 400, 600 # 창 크기
FPS = 60 # 초당 60프레임
WHITE = (255, 255, 255)
BLACK = (0,0,0)
BROWN = (150, 75, 0)
OBJECT_SIZE = 30
Python
복사
•
FallObject 클래스를 Player 클래스 아래에다가 붙여봅시다.
class FallObject:
def __init__(self):
x = random.randint(0, WIDTH - OBJECT_SIZE )
y = -OBJECT_SIZE # 화면 위(밖)에서 시작
self.rect = pygame.Rect(x, y, OBJECT_SIZE , OBJECT_SIZE )
self.speed = 5 # 낙하 속도
def update(self):
self.rect.y += self.speed
def draw(self, screen):
cx, cy = self.rect.center
r = OBJECT_SIZE // 2
pygame.draw.circle(screen, BROWN, (cx, cy), r)
Python
복사
•
Game 클래스 Player 생성 아래에다가 리스트와 스폰 타이머를 추가하겠습니다.
class Game:
def __init__(self):
pygame.init() # Pygame 초기화
#위에서 설정한 변수로 게임 스크린 크기 설정
self.screen = pygame.display.set_mode((WIDTH, HEIGHT))
# 창 제목 설정
pygame.display.set_caption("Suberunker Game")
# FPS를 제어해주는 '시계' 생성
self.clock = pygame.time.Clock()
#run이라는 함수를 계속 돌릴지 여부
self.running = True
# 플레이어 화면 아래 중앙 배치
px = WIDTH//2 - 20; py = HEIGHT - 60
self.player = Player(px, py, 40, 40, 5, BLACK)
# 떨어지는 오브젝트 리스트
self.objects = []
# 일정 주기로 자동 생성되는 이벤트
self.SPAWN = pygame.USEREVENT + 1
pygame.time.set_timer(self.SPAWN, 600)
Python
복사
•
아래와 같이 spawn_object, update_objects, draw_objects 메서드를 만들겠습니다.
class Game:
def __init__(self): # Game 객체가 만들어질 때 한 번 실행
pygame.init() # 1) Pygame 내부 모듈 초기화
self.screen = pygame.display.set_mode( # 2) 게임 창(스크린) 만들기
(WIDTH, HEIGHT)
)
pygame.display.set_caption("Suberunker Game")# 3) 창 제목(캡션) 지정
self.clock = pygame.time.Clock() # 4) FPS를 제어해주는 '시계' 생성
self.running = True # 5) 메인 루프를 돌릴지 여부(True면 계속)
# 플레이어 화면 아래 중앙 배치
px = WIDTH//2 - 20; py = HEIGHT - 60
self.player = Player(px, py, 40, 40, 5, BLACK)
# 떨어지는 오브젝트 리스트
self.objects = []
# 일정 주기로 자동 생성되는 이벤트
self.SPAWN = pygame.USEREVENT + 1
pygame.time.set_timer(self.SPAWN, 600)
def spawn_object(self):
self.objects.append(FallObject())
def update_objects(self):
for p in self.objects[:]:
p.update()
def draw_objects(self):
for p in self.objects:
p.draw(self.screen)
Python
복사
•
Game클래스의 run메서드를 아래와 같이 추가합니다. 갱신되어야 하는 시점에 플레이어 입력과 같이 오브젝트도 떨어뜨릴 수 있게 하겠습니다.
def run(self):
while self.running: # running이 True인 동안 계속 반복
self.clock.tick(FPS) # 프레임 속도 제어
for e in pygame.event.get(): # 마우스/키보드 등 이벤트를 꺼낸다.
if e.type == pygame.QUIT: # 꺼낸 이벤트가 종료라면 running을
self.running = False # false로 만들어서 게임 종료.
self.player.handle_input() # 입력처리
self.update_objects()
self.screen.fill(WHITE) # 배경을 하얀색으로 칠하고
self.player.draw(self.screen) # 플레이어 그리기
self.draw_objects()
pygame.display.flip() # 화면 업데이트
pygame.quit() #Pygame 닫기
sys.exit() #파이썬 프로그램 완전 종료
Python
복사
•
여기까지 잘 따라오셨으면 아래와 같이 동그라미 오브젝트가 떨어지는 것을 확인할 수 있습니다.
부딪히면 게임 종료
•
이제 충돌 처리를 해보겠습니다.
•
지난 공룡 게임에서 활용했던 colliderect를 활용해 보겠습니다.
•
아래와 같이 Game 클래스에 check_collision 메서드를 추가해 주세요.
def check_collision(self):
for p in self.objects:
if self.player.rect.colliderect(p.rect):
self.running = False # ← '맞으면 끝'
break
Python
복사
•
그리고 우리의 게임이 돌아가고 있는 run으로 와서 이제 저 메서드를 호출해야 합니다. 어디서 호출하는 게 좋을까요?
•
바로, 장애물이 움직이고 난 뒤인 update_objects() 직후입니다.
def run(self):
while self.running: # running이 True인 동안 계속 반복
self.clock.tick(FPS) # 프레임 속도 제어
for e in pygame.event.get(): # 마우스/키보드 등 이벤트를 꺼낸다.
if e.type == pygame.QUIT: # 꺼낸 이벤트가 종료라면 running을
self.running = False # false로 만들어서 게임 종료.
self.player.handle_input() # 입력처리
self.update_objects()
self.check_collision() # 충돌감지
self.screen.fill(WHITE) # 배경을 하얀색으로 칠하고
self.player.draw(self.screen) # 플레이어 그리기
self.draw_objects()
pygame.display.flip() # 화면 업데이트
pygame.quit() #Pygame 닫기
sys.exit() #파이썬 프로그램 완전 종료
Python
복사
여기까지 잘 따라오셨다면, 실행하고 나서 떨어지는 오브젝트와 충돌나면 게임이 종료될 것입니다.
게임이 갑자기 툭 꺼져도 정상이니 걱정하지 않으셔도 됩니다 
이렇게 한 줄 한 줄 쌓다 보니 벌써 게임이 완성됐습니다.
“게임은 즐기는 것”이기도 하지만, “직접 만드는 것”은 더 큰 즐거움이라는 것을 학생들에게 알려주는 것은 어떨까요?
다음 호에서는 점수와 다양한 요소를 더해, 이 게임을 더 발전된 글로 찾아뵙겠습니다