반응형
파이썬으로 만드는 팩맨 게임: 미로 속 짜릿한 추격전을 코드로!🐍🎮
안녕하세요! Python Game Dev 블로그의 스무 번째 포스팅입니다. 지난 포스팅에서는 추억의 슈팅 게임 '갤러그'를 파이썬으로 구현해 보았는데요, 오늘은 약속드린 대로 고전 아케이드 게임의 대명사 '팩맨'을 Pygame으로 만들어 보겠습니다. 노란 팩맨이 미로를 누비며 유령을 피하는 짜릿한 경험을 코드로 함께 만들어 보세요!
오늘의 게임: 파이썬으로 만드는 팩맨 게임👾🧱
팩맨은 1980년대 초반 아케이드 게임 시장을 휩쓸었던 전설적인 게임입니다. 단순한 조작과 중독성 강한 게임 플레이는 전 세계적으로 큰 인기를 끌었죠. 오늘은 Pygame 라이브러리를 사용하여 이 고전 게임을 현대적인 컴퓨터 환경에서 즐길 수 있도록 만들어 보겠습니다.
게임의 규칙📜
- 플레이어는 팩맨을 조종하여 미로 속의 모든 점을 먹어야 합니다.
- 유령들은 팩맨을 쫓아다니며, 팩맨과 접촉하면 생명을 잃습니다.
- 파워 알약을 먹으면 일정 시간 동안 팩맨이 유령을 잡아먹을 수 있습니다.
- 모든 점을 먹거나 특정 조건을 만족하면 다음 단계로 넘어갑니다.
- (선택 사항) 다양한 유령 패턴, 보너스 아이템, 추가 미로 등을 추가하여 게임의 재미를 높일 수 있습니다.
전체 코드 💻
import pygame
import random
# Pygame 초기화
pygame.init()
# 화면 설정
screen_width = 600
screen_height = 600
screen = pygame.display.set_mode((screen_width, screen_height))
pygame.display.set_caption("팩맨 게임")
# 색상 정의
black = (0, 0, 0)
white = (255, 255, 255)
yellow = (255, 255, 0)
red = (255, 0, 0)
pink = (255, 192, 203)
cyan = (0, 255, 255)
orange = (255, 165, 0)
blue = (0, 0, 255)
# 미로 설정
maze = [
"############################",
"#............##............#",
"#.####.#####.##.#####.####.#",
"#o####.#####.##.#####.####o#",
"#.####.#####.##.#####.####.#",
"#..........................#",
"#.####.##.########.##.####.#",
"#.####.##.########.##.####.#",
"#......##....##....##......#",
"######.#####.##.#####.######",
"######.#####.##.#####.######",
"######.##..........##.######",
"######.##.########.##.######",
"######.##.########.##.######",
"#............##............#",
"#.####.#####.##.#####.####.#",
"#o####.#####.##.#####.####o#",
"#.####.#####.##.#####.####.#",
"#..........................#",
"############################",
]
maze_width = len(maze[0])
maze_height = len(maze)
tile_size = 20
# 팩맨 설정
pacman_radius = tile_size // 2
pacman_x = tile_size + pacman_radius
pacman_y = tile_size * 9 + pacman_radius
pacman_speed = 2
pacman_direction = 0 # 0: 오른쪽, 1: 왼쪽, 2: 위쪽, 3: 아래쪽
dirction_reserve = 0
# 유령 설정
ghost_radius = tile_size // 2
ghost_speed = 2
ghosts = [
[tile_size * 9 + ghost_radius, tile_size * 8 + ghost_radius, red, random.randint(0, 3)], # 유령 1
[tile_size * 10 + ghost_radius, tile_size * 8 + ghost_radius, pink, random.randint(0, 3)], # 유령 2
[tile_size * 9 + ghost_radius, tile_size * 9 + ghost_radius, cyan, random.randint(0, 3)], # 유령 3
[tile_size * 10 + ghost_radius, tile_size * 9 + ghost_radius, orange, random.randint(0, 3)], # 유령 4
]
# 점 설정
dot_radius = 4
dots = []
for y, row in enumerate(maze):
for x, tile in enumerate(row):
if tile == ".":
dots.append((x * tile_size + tile_size // 2, y * tile_size + tile_size // 2))
# 파워 알약 설정
power_pellet_radius = 8
power_pellets = []
for y, row in enumerate(maze):
for x, tile in enumerate(row):
if tile == "o":
power_pellets.append((x * tile_size + tile_size // 2, y * tile_size + tile_size // 2))
power_pellet_timer = 0
power_pellet_duration = 5000 # 5초
# 게임 루프
running = True
clock = pygame.time.Clock()
def check_wall_collision(x, y, dirction):
if (dirction == 0):
x += 1
if (dirction == 1):
x -= 1
if (dirction == 2):
y -= 1
if (dirction == 3):
y += 1
if maze[y][x] != "#":
return False
return True
while running:
# 이벤트 처리
pacman_grid_x = (pacman_x - pacman_radius) // tile_size
pacman_grid_y = (pacman_y - pacman_radius) // tile_size
pacman_x_moving = (pacman_x - pacman_radius) % tile_size
pacman_y_moving = (pacman_y - pacman_radius) % tile_size
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_RIGHT:
if pacman_y_moving == 0:
if check_wall_collision(pacman_grid_x, pacman_grid_y, 0) == False:
pacman_direction = 0
dirction_reserve = 0
else:
dirction_reserve = 0
elif event.key == pygame.K_LEFT:
if pacman_y_moving == 0:
if check_wall_collision(pacman_grid_x, pacman_grid_y, 1) == False:
pacman_direction = 1
dirction_reserve = 1
else:
dirction_reserve = 1
if event.key == pygame.K_UP:
if pacman_x_moving == 0:
if check_wall_collision(pacman_grid_x, pacman_grid_y, 2) == False:
pacman_direction = 2
dirction_reserve = 2
else:
dirction_reserve = 2
elif event.key == pygame.K_DOWN:
if pacman_x_moving == 0:
if check_wall_collision(pacman_grid_x, pacman_grid_y, 3) == False:
pacman_direction = 3
dirction_reserve = 3
else:
dirction_reserve = 3
if (pacman_x_moving == 0) & (pacman_y_moving == 0):
if pacman_direction != dirction_reserve:
if check_wall_collision(pacman_grid_x, pacman_grid_y, dirction_reserve) == False:
pacman_direction = dirction_reserve
# 팩맨 이동
new_pacman_x, new_pacman_y = pacman_x, pacman_y
if pacman_direction == 0:
new_pacman_x += pacman_speed
elif pacman_direction == 1:
new_pacman_x -= pacman_speed
elif pacman_direction == 2:
new_pacman_y -= pacman_speed
elif pacman_direction == 3:
new_pacman_y += pacman_speed
# 팩맨 벽 충돌 처리
if (pacman_direction == 0) & (pacman_x_moving == 0):
pacman_grid_x += 1
if (pacman_direction == 1) & (pacman_x_moving == 0):
pacman_grid_x -= 1
if (pacman_direction == 2) & (pacman_y_moving == 0):
pacman_grid_y -= 1
if (pacman_direction == 3) & (pacman_y_moving == 0):
pacman_grid_y += 1
if maze[pacman_grid_y][pacman_grid_x] != "#":
pacman_x, pacman_y = new_pacman_x, new_pacman_y
# 점 먹기 처리
for dot in dots[:]:
distance = ((pacman_x - dot[0]) ** 2 + (pacman_y - dot[1]) ** 2) ** 0.5
if distance < pacman_radius + dot_radius:
dots.remove(dot)
# 파워 알약 먹기 처리
for pellet in power_pellets[:]:
distance = ((pacman_x - pellet[0]) ** 2 + (pacman_y - pellet[1]) ** 2) ** 0.5
if distance < pacman_radius + power_pellet_radius:
power_pellets.remove(pellet)
power_pellet_timer = pygame.time.get_ticks()
# 파워 알약 지속 시간 처리
if power_pellet_timer > 0 and pygame.time.get_ticks() - power_pellet_timer > power_pellet_duration:
power_pellet_timer = 0
# 유령 이동
for ghost in ghosts:
new_ghost_x, new_ghost_y = ghost[0], ghost[1]
if ghost[3] == 0:
new_ghost_x += ghost_speed
elif ghost[3] == 1:
new_ghost_x -= ghost_speed
elif ghost[3] == 2:
new_ghost_y -= ghost_speed
elif ghost[3] == 3:
new_ghost_y += ghost_speed
# 유령 벽 충돌 처리
ghost_grid_x = (ghost[0] - ghost_radius) // tile_size
ghost_grid_y = (ghost[1] - ghost_radius) // tile_size
new_ghost_x_moving = (ghost[0] - ghost_radius) % tile_size
new_ghost_y_moving = (ghost[1] - ghost_radius) % tile_size
if (ghost[3] == 0) & (new_ghost_x_moving == 0):
ghost_grid_x += 1
if (ghost[3] == 1) & (new_ghost_x_moving == 0):
ghost_grid_x -= 1
if (ghost[3] == 2) & (new_ghost_y_moving == 0):
ghost_grid_y -= 1
if (ghost[3] == 3) & (new_ghost_y_moving == 0):
ghost_grid_y += 1
if maze[ghost_grid_y][ghost_grid_x] != "#":
ghost[0], ghost[1] = new_ghost_x, new_ghost_y
else:
ghost[3] = random.randint(0, 3) # 벽에 부딪히면 방향 전환
# 팩맨과 유령 충돌 처리
distance = ((pacman_x - ghost[0]) ** 2 + (pacman_y - ghost[1]) ** 2) ** 0.5
if distance < pacman_radius + ghost_radius:
if power_pellet_timer > 0:
ghosts.remove(ghost)
else:
running = False # 게임 오버
is_log = False
# 화면 그리기
screen.fill(black)
# 미로 그리기
for y, row in enumerate(maze):
for x, tile in enumerate(row):
if tile == "#":
pygame.draw.rect(screen, blue, (x * tile_size, y * tile_size, tile_size, tile_size))
# 점 그리기
for dot in dots:
pygame.draw.circle(screen, white, dot, dot_radius)
# 파워 알약 그리기
for pellet in power_pellets:
pygame.draw.circle(screen, white, pellet, power_pellet_radius)
# 팩맨 그리기
pygame.draw.circle(screen, yellow, (pacman_x, pacman_y), pacman_radius)
# 유령 그리기
for ghost in ghosts:
pygame.draw.circle(screen, ghost[2], (ghost[0], ghost[1]), ghost_radius)
# 화면 업데이트
pygame.display.flip()
clock.tick(60)
pygame.quit()
게임 화면📸
- 팩맨은 화면 중앙에서 시작하며, 화살표 키로 조종할 수 있습니다.
- 유령들은 화면 곳곳을 돌아다니며, 팩맨을 쫓아다닙니다.
- 점은 미로 곳곳에 흩어져 있으며, 팩맨은 점을 먹어 점수를 얻습니다.
- 파워 알약은 특정 위치에 있으며, 먹으면 유령을 잡아먹을 수 있습니다.
코드 설명📝
- 팩맨: Pygame의 draw.circle() 함수를 사용하여 원 모양으로 그립니다.
- 유령: 리스트를 사용하여 여러 개의 유령을 관리하고, 각 유령의 위치와 색상을 설정합니다.
- 점: 리스트를 사용하여 여러 개의 점을 관리하고, 각 점의 위치를 설정합니다.
- 파워 알약: 리스트를 사용하여 파워 알약의 위치를 설정하고, 팩맨과의 충돌 시 타이머를 작동시킵니다.
- 충돌 처리: 팩맨과 점, 팩맨과 유령, 팩맨과 파워 알약 간의 충돌을 감지하고, 해당 객체를 제거하거나 게임 오버를 처리합니다.
게임 실행 방법🚀
- 파이썬과 Pygame 라이브러리를 설치합니다.
- 위의 코드를 복사하여 Python 파일로 저장합니다.
- 터미널 또는 명령 프롬프트에서 해당 파일을 실행합니다.
게임에서 사용된 프로그래밍 개념📚
- 리스트: 여러 개의 유령, 점, 파워 알약을 관리하기 위해 리스트를 사용합니다.
- 랜덤 함수: 유령의 이동 방향을 랜덤하게 설정하기 위해 random 모듈의 함수를 사용합니다.
- 충돌 감지: 객체 간의 충돌을 감지하기 위해 원형 충돌 검사를 사용합니다.
- 타이머: 파워 알약의 지속 시간을 관리하기 위해 Pygame의 타이머 기능을 사용합니다.
알고리즘 설명🧮
- 유령 이동 알고리즘: 유령은 랜덤한 방향으로 이동하며, 화면 경계에 도달하면 방향을 바꿉니다.
- 충돌 감지 알고리즘: 팩맨과 유령, 팩맨과 점, 팩맨과 파워 알약 간의 거리를 계산하여 충돌 여부를 판단합니다.
- 파워 알약 알고리즘: 팩맨이 파워 알약을 먹으면 타이머가 시작되고, 타이머가 종료되면 효과가 사라집니다.
확장 가능성 🌱
- 다양한 유령 패턴: 유령의 이동 패턴을 다양하게 추가하고, 각 유령에 따라 다른 전략을 사용하도록 설정할 수 있습니다.
- 미로 생성: 2차원 배열을 사용하여 미로를 생성하고, 팩맨과 유령이 미로를 따라 이동하도록 설정할 수 있습니다.
- 보너스 아이템: 팩맨의 속도를 증가시키거나 유령을 일시적으로 멈추게 하는 보너스 아이템을 추가할 수 있습니다.
- 배경 음악 및 효과음: 게임의 분위기를 고조시키는 배경 음악과 효과음을 추가할 수 있습니다.
다음 포스팅 예고 🔮
다음 포스팅에서는 '파이썬으로 만드는 레이싱 게임(Racing Game)'에 대해 알아보겠습니다. 짜릿한 속도감을 느낄 수 있는 레이싱 게임을 Pygame으로 구현해 볼 예정입니다. 플레이어 차량 조작, AI 차량 생성 및 이동, 트랙 생성, 충돌 처리, 점수 시스템 등 게임의 핵심 요소들을 구현하는 방법을 자세히 살펴보겠습니다. 또한, 다양한 트랙 디자인, 차량 업그레이드, 그리고 화려한 시각 효과를 통해 게임의 재미를 더욱 높이는 방법도 함께 배워볼 계획입니다. 🐍✨
반응형
'파이썬 기초문법 > 파이썬 게임 만들기' 카테고리의 다른 글
파이썬 게임 만들기 - 레이싱 게임 🏁🏎️ (2) | 2025.03.19 |
---|---|
파이썬 게임 만들기 - 갤러그 게임🚀👾 (0) | 2025.03.18 |
파이썬 게임 만들기 - 미로 탈출 게임 ️🧠🧩 (0) | 2025.03.15 |
파이썬 게임 만들기 - 두더지 잡기 게임 🦔🔨 (1) | 2025.03.15 |
파이썬 게임 만들기 - 플래피 버드 🐦🌵 (1) | 2025.03.15 |