안녕하세요? 초코쌤입니다.
10월호에서는
•
큰 틀 잡기 → 플레이어를 움직일 수 있게 하기 →떨어지는 도형 만들기 → 부딪히면 게임 종료
이렇게까지 했었는데요.
이번호에서는 아래 4단계를 하려고 합니다.
먼저, 지난시간에 했던 스베랑카 게임을 키면 위와 같이 화면이 나올 것입니다. 이 게임을 오른쪽으로 변화시키는 것이 목표입니다!
import pygame #Pygame 기능 쓰기 위함
import sys #sys.exit()를 사용하기 위함
import random
WIDTH, HEIGHT = 400, 600 # 창 크기
FPS = 60 # 초당 60프레임
WHITE = (255, 255, 255)
BLACK = (0,0,0)
BROWN = (150, 75, 0)
OBJECT_SIZE = 30
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)
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)
class Game:
def __init__(self): # Pygame 초기화
pygame.init()
#위에서 설정한 변수로 게임 스크린 크기 설정
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)
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)
def check_collision(self):
for p in self.objects:
if self.player.rect.colliderect(p.rect):
self.running = False # ← '맞으면 끝'
break
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로 만들어서 게임 종료.
if e.type == self.SPAWN:
self.spawn_object()
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() #파이썬 프로그램 완전 종료
game = Game()
game.run()
Python
복사
지난 시간에 했던 코드입니다. 이번호부터 보시는 분들은 이걸 복사해서 같이 따라해보시죠.
떨어지는 도형 화면 밖으로 나가면 삭제하기
1.
게임 루프 확인
self.player.handle_input() # 입력처리
self.update_objects()
self.check_collision() # 충돌감지
Python
복사
•
지금 이 게임은 매 프레임마다 이렇게 동작하고 있는데요. 지금 떨어지는 오브젝트들이 화면 밖으로 벗어나도 저 떨어지는 오브젝트가 화면에서만 안보일 뿐, 실제로 사라지고 있지는 않습니다.
•
즉, 가지고 있는 떨어지는 오브젝트들이 update하고 이후에는 또 그려질텐데, 화면에만 안보일뿐 계속 늘어나고 있다는 겁니다.
⇒ 이렇게되면 연산량이 많아져서 게임을 계속 플레이하다보면 렉걸린 것처럼 느껴지게 될겁니다.
1.
update_objects 메서드 수정
def update_objects(self):
for p in self.objects[:]:
p.update()
# 화면 아래로 완전히 벗어났다면 제거
if p.rect.top > HEIGHT:
self.objects.remove(p)
Python
복사
•
update_objects메서드에 remove()를 위와 같이 추가하여 화면 아래로 벗어났다면 제거하도록 하겠습니다.
떨어지는 오브젝트 속도 다르게 하기
- 지금은 모든 오브젝트가 동일한 속도로 떨어지고 있습니다. 이러면 게임이 지루해지겠죠? 속도를 다르게 해서 긴장감을 조성해봅시다!
1.
FallObject 생성자 수정
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 = random.randint(3, 8) # 낙하 속도
Python
복사
•
위와 같이 수정하고 게임을 실행시켜본다면, 아래와 같이 오브젝트마다 속도가 달라져서 피해야 하는 긴장감이 더해질 겁니다!
점수 추가
•
이번에는 플레이어가 얼마나 잘 피했는지 확인할 수 있게 점수를 추가하겠습니다. 점수는 떨어지는 오브젝트가 화면 아래로 무사히 내려가면 1점씩 부여할게요! 잘피했다는 의미죠 ㅎㅎ
1.
Game 생성자 수정
class Game:
def __init__(self): # Pygame 초기화
pygame.init()
#위에서 설정한 변수로 게임 스크린 크기 설정
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)
# 점수
self.score = 0
# 폰트
self.font = pygame.font.Font(None,32)
Python
복사
•
Game 생성자에 score를 0으로 초기화하고, 폰트도 기본 폰트로 32크기로 쓰겠습니다.
2.
Game update_objects 수정
def update_objects(self):
for p in self.objects[:]:
p.update()
# 화면 아래로 완전히 벗어났다면 제거
if p.rect.top > HEIGHT:
self.objects.remove(p)
self.score +=1
Python
복사
•
여기다가 화면 아래로 벗어나는 제거하는 순간에 score를 증가시켜주겠습니다.
3.
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로 만들어서 게임 종료.
if e.type == self.SPAWN:
self.spawn_object()
self.player.handle_input() # 입력처리
self.update_objects()
self.check_collision() # 충돌감지
self.screen.fill(WHITE) # 배경을 하얀색으로 칠하고
self.player.draw(self.screen) # 플레이어 그리기
self.draw_objects()
score_text = self.font.render(f"Score : {self.score}", True, BLACK)
self.screen.blit(score_text, (10, 10))
pygame.display.flip() # 화면 업데이트
pygame.quit() #Pygame 닫기
sys.exit() #파이썬 프로그램 완전 종료
Python
복사
•
증가되고 있는 score를 그려주는 함수를 추가하겠습니다.
이미지 추가
1.
이미지 찾기 및 다운로드
•
게임 이미지는 다양한 곳에서 찾을 수 있지만, 많이 쓰는 사이트 중 하나인 https://opengameart.org/ 에서 찾아서 플레이어는 가공을 조금 해가지고 드리겠습니다. 아래 2개의 이미지를 각각 플레이어와 떨어지는 오브젝트에 적용시키겠습니다.
•
위 파일 2개를 다운받아주세요.
이미지 출처)
•
떨어지는 돌:
OpenGameArt.orgRock
Player sprite: Free to use, no attribution required (Original Author)
Rock sprite: Viktor Hahn, CC BY 4.0
https://creativecommons.org/licenses/by/4.0/
Python
복사
2.
이미지 옮기기
•
이렇게 다운받은 파일을 옮겨주세요!
3.
이미지 불러오기 - Game 생성자에 추가
class Game:
def __init__(self): # Pygame 초기화
pygame.init()
#위에서 설정한 변수로 게임 스크린 크기 설정
self.screen = pygame.display.set_mode(
(WIDTH, HEIGHT)
)
# 창 제목 설정
pygame.display.set_caption("Suberunker Game")
# FPS를 제어해주는 '시계' 생성
self.clock = pygame.time.Clock()
#run이라는 함수를 계속 돌릴지 여부
self.running = True
# 이미지
self.player_img = pygame.image.load("player.png")
self.object_img = pygame.image.load("fallobject.png")
# 플레이어 화면 아래 중앙 배치
px = WIDTH//2 - 20; py = HEIGHT - 60
self.player = Player(px, py, 26, 31, 5, BLACK,self.player_img)
# 떨어지는 오브젝트 리스트
self.objects = []
# 일정 주기로 자동 생성되는 이벤트
self.SPAWN = pygame.USEREVENT + 1
pygame.time.set_timer(self.SPAWN, 600)
# 점수
self.score = 0
# 폰트
self.font = pygame.font.Font(None,32)
Python
복사
•
받은 파일을 추가해봅시다.
4.
Player 및 FallObject 클래스 수정
class Player:
def __init__(self, x, y, w, h, speed, color,image=None):
self.rect = pygame.Rect(x, y, w, h) # 위치/크기
self.speed = speed # 한 프레임당 이동 픽셀
self.color = color
self.image = image
def draw(self, screen):
# 플레이어(검정 사각형) 그리기
#pygame.draw.rect(screen, self.color, self.rect)
screen.blit(self.image, self.rect.topleft)
class FallObject:
def __init__(self,image=None):
x = random.randint(0, WIDTH - OBJECT_SIZE )
y = -OBJECT_SIZE # 화면 위(밖)에서 시작
self.rect = pygame.Rect(x, y, OBJECT_SIZE , OBJECT_SIZE )
self.speed = random.randint(3, 8) # 낙하 속도
self.image= image
def draw(self, screen):
screen.blit(self.image,self.rect.topleft)
#cx, cy = self.rect.center
#r = OBJECT_SIZE // 2
#pygame.draw.circle(screen, BROWN, (cx, cy), r)
Python
복사
•
생성자에서 image를 받아서 멤버로 들고있고, draw에서 이미지를 그려주는 함수로 변경하겠습니다.
5.
이미지에 맞춰서 플레이어와 오브젝트 크기 조절
OBJECT_SIZE = 32
Python
복사
•
돌 크기가 32라서 이렇게 변경해주세요.
self.player = Player(px, py, 26, 31, 5, BLACK,self.player_img)
Python
복사
•
플레이어 이미지는 26x31이기때문에 Game 생성자에 플레이어 크기 값을 변경해주세요.
여기까지 잘 따라오셨다면 위와 같이 떨어지는 오브젝트는 돌로, 플레이어는 사각형에서 귀여운 캐릭터로 변경된 것을 확인할 수 있습니다!
기본틀이 완성된 상태에서 하나씩 기능을 추가하고 구조를 이해하다 보니, 단순한 예제게임이 조금 더 ‘게임다운’ 모습으로 발전했죠?
이런 수업을 진행하게 되면 게임이 단순 플레이하는 대상이 아니라, 논리와 상상력으로 만들어가는 결과물이라는 것을 학생들이 느끼게 될 것입니다.
프로그래밍 언어를 단순히 배우고 끝나는 것이 아니라, 흥미로운 게임 개발로 이어진다면 학생들에게 이보다 더 좋은 동기부여는 없지 않을까요? 
다음에 더 발전된 게임으로 찾아뵙겠습니다. 감사합니다.







