파이썬 기초문법/파이썬 게임 만들기
파이썬 게임 만들기 - 플래피 버드 🐦🌵
Family in August
2025. 3. 15. 10:24
반응형
파이썬으로 만드는 플래피 버드: 단순함 속의 중독성 🐍🎮🐦
안녕하세요! Python Game Dev 블로그의 열여섯 번째 포스팅입니다. 지난 포스팅에서는 고전 게임 테트리스를 구현해보았는데요. 오늘은 약속드린 대로 '파이썬으로 만드는 플래피 버드(Flappy Bird)'를 만들어보겠습니다. 모바일 게임계를 강타했던 이 단순하면서도 중독성 강한 게임을 Pygame으로 함께 구현해봅시다!
오늘의 게임: 파이썬으로 만드는 플래피 버드 🐦🌵
플래피 버드는 2013년 베트남 개발자 응우옌 하 동(Dong Nguyen)이 개발한 게임으로, 단순한 메커니즘에도 불구하고 엄청난 인기를 끌었습니다. 화면을 터치하여 새를 점프시키고 파이프 장애물을 피하는 간단한 게임이지만, 그 어려움과 중독성으로 전 세계적인 현상이 되었죠. 오늘은 Pygame 라이브러리를 사용해 이 게임을 재현해보겠습니다.
게임의 규칙 📜
- 플레이어는 작은 새(버드)를 조종합니다
- 스페이스바를 누르면 새가 위로 점프합니다
- 아무 입력이 없으면 새는 중력에 의해 떨어집니다
- 파이프 장애물이 일정한 간격으로 나타납니다
- 파이프 사이의 빈 공간을 통과해야 합니다
- 파이프나 바닥, 천장에 부딪히면 게임 오버됩니다
- 각 파이프를 성공적으로 통과할 때마다 점수가 1점씩 증가합니다
- 게임의 목표는 최대한 많은 점수를 획득하는 것입니다
전체 코드 💻
import pygame
import sys
import random
# 게임 초기화
pygame.init()
# 화면 설정
WIDTH, HEIGHT = 400, 600
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption('파이썬으로 만드는 플래피 버드')
# 색상 정의
WHITE = (255, 255, 255)
BLUE = (0, 0, 255)
GREEN = (0, 255, 0)
BLACK = (0, 0, 0)
RED = (255, 0, 0)
YELLOW = (255, 255, 0)
# 게임 변수
gravity = 0.25
bird_movement = 0
score = 0
high_score = 0
game_active = False
score_font = pygame.font.SysFont('malgungothic', 30)
game_over_font = pygame.font.SysFont('malgungothic', 40)
# 배경 설정
bg_surface = pygame.Surface((WIDTH, HEIGHT))
bg_surface.fill((113, 197, 207)) # 하늘색 배경
# 바닥 설정
floor_surface = pygame.Surface((WIDTH, 100))
floor_surface.fill((222, 216, 149)) # 황토색 바닥
floor_y_pos = HEIGHT - 100
# 새(플레이어) 설정
class Bird:
def __init__(self):
self.x = 100
self.y = HEIGHT // 2
self.radius = 15
self.movement = 0
self.alive = True
def draw(self):
# 새의 몸체
pygame.draw.circle(screen, YELLOW, (self.x, self.y), self.radius)
# 새의 눈
pygame.draw.circle(screen, BLACK, (self.x + 8, self.y - 5), 4)
# 새의 부리
pygame.draw.polygon(screen, RED, [(self.x + 15, self.y), (self.x + 25, self.y), (self.x + 15, self.y + 5)])
def apply_gravity(self):
self.movement += gravity
self.y += self.movement
def jump(self):
self.movement = -5
def check_collision(self, pipes):
# 바닥 또는 천장 충돌 확인
if self.y <= 0 or self.y >= floor_y_pos - self.radius:
return True
# 파이프 충돌 확인
for pipe in pipes:
# 상단 파이프 충돌
if self.x + self.radius > pipe.x and self.x - self.radius < pipe.x + pipe.width:
if self.y - self.radius < pipe.height:
return True
# 하단 파이프 충돌
if self.x + self.radius > pipe.x and self.x - self.radius < pipe.x + pipe.width:
if self.y + self.radius > pipe.height + pipe.gap:
return True
return False
# 파이프(장애물) 설정
class Pipe:
def __init__(self):
self.x = WIDTH + 100
self.height = random.randint(150, 350)
self.gap = 150 # 파이프 사이 간격
self.width = 60
self.passed = False
self.speed = 2
def move(self):
self.x -= self.speed
def draw(self):
# 상단 파이프
pygame.draw.rect(screen, GREEN, (self.x, 0, self.width, self.height))
# 하단 파이프
pygame.draw.rect(screen, GREEN, (self.x, self.height + self.gap, self.width, HEIGHT - self.height - self.gap - 100))
# 파이프 상단과 하단에 테두리 추가
pygame.draw.rect(screen, (34, 139, 34), (self.x, self.height - 20, self.width + 10, 20))
pygame.draw.rect(screen, (34, 139, 34), (self.x, self.height + self.gap, self.width + 10, 20))
# 게임 재시작 함수
def reset_game():
global bird, pipes, score, game_active
bird = Bird()
pipes = [Pipe()]
score = 0
game_active = True
# 객체 생성
bird = Bird()
pipes = [Pipe()]
pipe_spawn_timer = 0
# 게임 루프
clock = pygame.time.Clock()
while True:
# 이벤트 처리
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
if game_active:
bird.jump()
else:
reset_game()
# 배경 그리기
screen.blit(bg_surface, (0, 0))
if game_active:
# 새 업데이트
bird.apply_gravity()
bird.draw()
# 파이프 업데이트
pipe_spawn_timer += 1
if pipe_spawn_timer >= 120: # 약 2초마다 새 파이프 생성
pipes.append(Pipe())
pipe_spawn_timer = 0
# 파이프 그리기 및 이동
pipes_to_remove = []
for pipe in pipes:
pipe.move()
pipe.draw()
# 파이프 통과 점수 처리
if pipe.x + pipe.width < bird.x and not pipe.passed:
score += 1
pipe.passed = True
# 화면 밖으로 나간 파이프 제거
if pipe.x < -pipe.width:
pipes_to_remove.append(pipe)
# 파이프 제거
for pipe in pipes_to_remove:
pipes.remove(pipe)
# 충돌 감지
if bird.check_collision(pipes):
game_active = False
if score > high_score:
high_score = score
# 점수 표시
score_text = score_font.render(f'점수: {score}', True, WHITE)
screen.blit(score_text, (10, 10))
else:
# 게임 오버 화면
game_over_text = game_over_font.render('GAME OVER', True, RED)
score_text = score_font.render(f'점수: {score}', True, WHITE)
high_score_text = score_font.render(f'최고 점수: {high_score}', True, WHITE)
restart_text = score_font.render('스페이스바를 눌러 재시작', True, WHITE)
screen.blit(game_over_text, (WIDTH // 2 - game_over_text.get_width() // 2, HEIGHT // 3))
screen.blit(score_text, (WIDTH // 2 - score_text.get_width() // 2, HEIGHT // 3 + 50))
screen.blit(high_score_text, (WIDTH // 2 - high_score_text.get_width() // 2, HEIGHT // 3 + 90))
screen.blit(restart_text, (WIDTH // 2 - restart_text.get_width() // 2, HEIGHT // 3 + 150))
# 바닥 그리기
screen.blit(floor_surface, (0, floor_y_pos))
# 화면 업데이트
pygame.display.update()
clock.tick(60) # 60 FPS
게임 화면 📸
게임이 실행되면 다음과 같은 화면이 표시됩니다:
- 시작 화면: 게임을 시작하기 전 플레이어에게 스페이스바를 누르라는 안내가 표시됩니다.
- 게임 플레이 화면: 하늘색 배경에 노란색 새와 녹색 파이프가 보입니다. 화면 상단에는 현재 점수가 표시됩니다.
- 게임 오버 화면: 충돌 후 'GAME OVER' 메시지와 함께 점수, 최고 점수, 재시작 안내가 표시됩니다.
화면 구성요소
- 배경: 하늘색 배경으로 게임의 분위기를 조성합니다.
- 새(버드): 노란색 원형 몸체와 눈, 부리를 가진 플레이어 캐릭터입니다.
- 파이프: 상단과 하단에 위치한 녹색 파이프로, 사이의 간격을 통과해야 합니다.
- 바닥: 황토색 바닥으로 새가 떨어지면 충돌이 발생합니다.
- 점수: 화면 상단에 현재 점수가 표시됩니다.
코드 설명 📝
클래스 구조
- Bird 클래스:
- 새의 위치, 크기, 움직임을 관리합니다
- apply_gravity(): 중력 효과를 구현하여 새가 자연스럽게 떨어지도록 합니다
- jump(): 스페이스바를 누르면 새가 점프하는 기능을 구현합니다
- check_collision(): 파이프, 바닥, 천장과의 충돌을 감지합니다
- Pipe 클래스:
- 파이프의 위치, 높이, 너비, 간격을 관리합니다
- move(): 파이프가 왼쪽으로 일정 속도로 이동하도록 합니다
- draw(): 상단과 하단 파이프를 화면에 그립니다
주요 게임 매커니즘
1.중력 시스템:
def apply_gravity(self):
self.movement += gravity
self.y += self.movement
- 새의 움직임에 중력 상수를 더해 자연스러운 하강 효과를 구현합니다.
2. 점프 메커니즘:
def jump(self):
self.movement = -5
- 새의 움직임 값을 음수로 설정하여 위로 점프하는 효과를 구현합니다.
3. 충돌 감지:
def check_collision(self, pipes):
# 바닥 또는 천장 충돌 확인
if self.y <= 0 or self.y >= floor_y_pos - self.radius:
return True
# 파이프 충돌 확인
# ...
- 새의 위치를 파이프, 바닥, 천장의 위치와 비교하여 충돌을 감지합니다.
4. 점수 시스템:
if pipe.x + pipe.width < bird.x and not pipe.passed:
score += 1
pipe.passed = True
- 새가 파이프를 성공적으로 통과하면 점수가 증가합니다.
게임 실행 방법 🚀
- 파이썬과 Pygame 라이브러리가 설치되어 있어야 합니다.
- 위 코드를 flappy_bird.py 파일로 저장합니다.
- 터미널이나 명령 프롬프트에서 다음 명령어를 실행합니다:
python flappy_bird.py
- 게임이 시작되면 스페이스바를 눌러 새를 점프시키고 파이프를 피하세요!
- 게임 오버 후 다시 스페이스바를 눌러 재시작할 수 있습니다.
게임에서 사용된 프로그래밍 개념 📚
- 객체 지향 프로그래밍(OOP): Bird와 Pipe 클래스를 사용하여 게임 객체를 구조화했습니다.
- 이벤트 처리: Pygame의 이벤트 시스템을 사용하여 키보드 입력을 감지합니다.
- 물리 시뮬레이션: 중력 효과를 구현하여 현실적인 움직임을 만들어냅니다.
- 충돌 감지: 히트박스를 사용한 충돌 감지 알고리즘을 구현했습니다.
- 게임 루프: 일정한 프레임 속도로 게임을 업데이트하고 렌더링합니다.
- 랜덤 생성: 파이프의 높이를 무작위로 생성하여 매번 다른 게임 경험을 제공합니다.
알고리즘 설명 🧮
파이프 생성 알고리즘
pipe_spawn_timer += 1
if pipe_spawn_timer >= 120: # 약 2초마다 새 파이프 생성
pipes.append(Pipe())
pipe_spawn_timer = 0
- 일정 시간(약 2초)마다 새로운 파이프를 생성합니다.
- 이때 파이프의 높이는 무작위로 정해지며, 난이도와 다양성을 제공합니다.
충돌 감지 알고리즘
def check_collision(self, pipes):
# 바닥 또는 천장 충돌 확인
if self.y <= 0 or self.y >= floor_y_pos - self.radius:
return True
# 파이프 충돌 확인
for pipe in pipes:
# 상단 파이프 충돌
if self.x + self.radius > pipe.x and self.x - self.radius < pipe.x + pipe.width:
if self.y - self.radius < pipe.height:
return True
# 하단 파이프 충돌
if self.x + self.radius > pipe.x and self.x - self.radius < pipe.x + pipe.width:
if self.y + self.radius > pipe.height + pipe.gap:
return True
return False
- 새의 좌표와 파이프의 좌표를 비교하여 충돌을 감지합니다.
- 원형 히트박스와 사각형 충돌을 정확하게 계산합니다.
다음 포스팅 예고 🔮
다음 포스팅에서는 '파이썬으로 만드는 우주 슈팅 게임(Space Shooter)'에 대해 알아보겠습니다. 클래식 아케이드 스타일의 이 게임을 Pygame으로 구현해볼 예정입니다. 플레이어 우주선 제어, 적 생성 시스템, 다양한 무기 구현, 파티클 효과를 통한 폭발 애니메이션 등 게임의 핵심 요소들을 차근차근 살펴보겠습니다. 또한 난이도 증가 시스템과 보스 전투 기능도 추가하여 플레이어에게 도전적이고 재미있는 게임 경험을 제공하는 방법을 배워볼 계획입니다.
여러분의 의견과 질문은 언제나 환영합니다. 행복한 코딩 되세요! 🐍🎮✨
반응형