파이썬 기초문법/파이썬 게임 만들기

파이썬 게임 만들기 - 두더지 잡기 게임 🦔🔨

Family in August 2025. 3. 15. 18:06
반응형

파이썬으로 만드는 두더지 잡기 게임: 오락실의 추억을 코드로 🐍🎮🦔

안녕하세요! Python Game Dev 블로그의 열일곱 번째 포스팅입니다. 지난 포스팅에서는 중독성 강한 '플래피 버드' 게임을 구현해보았는데요. 오늘은 약속드린 대로 '파이썬으로 만드는 두더지 잡기 게임(Whack-a-Mole)'을 만들어보겠습니다. 오락실에서 한 번쯤 즐겨보셨을 이 게임을 Pygame으로 함께 구현해봅시다!

오늘의 게임: 파이썬으로 만드는 두더지 잡기 게임 🦔🔨

두더지 잡기는 오락실과 놀이공원에서 흔히 볼 수 있는 인기 게임입니다. 무작위로 나타나는 두더지를 망치로 빠르게 내리쳐 점수를 얻는 단순한 게임이지만, 순발력과 집중력을 요구하는 매력적인 게임이죠. 오늘은 Pygame 라이브러리를 사용해 이 게임을 컴퓨터에서 즐길 수 있도록 만들어보겠습니다.

게임의 규칙 📜

  • 게임은 3x3 격자 형태의 9개 구멍으로 구성됩니다.
  • 두더지는 무작위로 구멍에서 나타났다가 일정 시간 후 사라집니다.
  • 플레이어는 마우스로 두더지를 클릭하여 잡습니다.
  • 두더지를 잡으면 10점을 획득합니다.
  • 특별한 황금 두더지는 가끔 등장하며 50점을 획득할 수 있습니다.
  • 게임은 60초 동안 진행됩니다.
  • 시간이 지날수록 두더지가 나타나는 속도가 빨라집니다.

전체 코드 💻

import pygame
import sys
import random
import time

# 게임 초기화
pygame.init()
pygame.mixer.init()  # 사운드 시스템 초기화

# 화면 설정
WIDTH, HEIGHT = 800, 600
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("두더지 잡기 게임")

# 색상 정의
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
GREEN = (34, 139, 34)
BROWN = (139, 69, 19)
GOLD = (255, 215, 0)

# 폰트 설정
font = pygame.font.SysFont("malgungothic", 30)
large_font = pygame.font.SysFont("malgungothic", 50)

# 게임 사운드 로드
try:
    hit_sound = pygame.mixer.Sound("hit.wav")
    miss_sound = pygame.mixer.Sound("miss.wav")
    special_sound = pygame.mixer.Sound("special.wav")
except:
    print("사운드 파일을 찾을 수 없습니다. 효과음 없이 게임이 실행됩니다.")
    hit_sound = miss_sound = special_sound = None

# 두더지 클래스
class Mole:
    def __init__(self, x, y, size, is_special=False):
        self.x = x
        self.y = y
        self.size = size
        self.is_visible = False
        self.appear_time = 0
        self.hide_time = 0
        self.is_special = is_special
        self.hit = False
    
    def show(self, current_time, duration):
        self.is_visible = True
        self.appear_time = current_time
        self.hide_time = current_time + duration
        self.hit = False
    
    def hide(self):
        self.is_visible = False
    
    def update(self, current_time):
        if self.is_visible and current_time > self.hide_time and not self.hit:
            self.hide()
    
    def check_hit(self, pos):
        if not self.is_visible or self.hit:
            return False
        
        distance = ((pos[0] - self.x) ** 2 + (pos[1] - self.y) ** 2) ** 0.5
        if distance < self.size / 2:
            self.hit = True
            self.hide()
            return True
        return False
    
    def draw(self, surface):
        if self.is_visible:
            # 두더지 구멍 그리기
            pygame.draw.circle(surface, BROWN, (self.x, self.y + self.size//4), self.size//2)
            
            # 두더지 그리기
            if self.is_special:
                color = GOLD  # 황금 두더지
            else:
                color = BLACK  # 일반 두더지
            
            pygame.draw.circle(surface, color, (self.x, self.y), self.size//3)
            
            # 두더지 눈 그리기
            eye_radius = self.size//12
            pygame.draw.circle(surface, WHITE, (self.x - self.size//8, self.y - self.size//12), eye_radius)
            pygame.draw.circle(surface, WHITE, (self.x + self.size//8, self.y - self.size//12), eye_radius)
            
            # 두더지 코 그리기
            pygame.draw.circle(surface, WHITE if self.is_special else BROWN, (self.x, self.y + self.size//12), eye_radius//2)
        else:
            # 빈 구멍만 그리기
            pygame.draw.circle(surface, BROWN, (self.x, self.y + self.size//4), self.size//2)

def main():
    clock = pygame.time.Clock()
    FPS = 60
    
    # 게임 상태
    game_active = False
    score = 0
    game_duration = 60  # 60초 게임
    start_time = 0
    
    # 두더지 초기화 (3x3 그리드)
    moles = []
    mole_size = 80
    padding = 100
    grid_size = 3
    
    for row in range(grid_size):
        for col in range(grid_size):
            x = padding + col * ((WIDTH - 2 * padding) // (grid_size - 1))
            y = padding + 100 + row * ((HEIGHT - 2 * padding - 100) // (grid_size - 1))
            moles.append(Mole(x, y, mole_size))
    
    # 배경 이미지 (간단한 잔디 패턴)
    background = pygame.Surface((WIDTH, HEIGHT))
    background.fill(GREEN)
    
    # 게임 로직
    while True:
        current_time = pygame.time.get_ticks() / 1000  # 초 단위 시간
        
        # 이벤트 처리
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()
            
            if event.type == pygame.MOUSEBUTTONDOWN:
                if not game_active:
                    # 게임 시작
                    game_active = True
                    score = 0
                    start_time = current_time
                else:
                    # 두더지 클릭 체크
                    pos = pygame.mouse.get_pos()
                    hit_any = False
                    
                    for mole in moles:
                        if mole.check_hit(pos):
                            hit_any = True
                            if mole.is_special:
                                score += 50
                                if special_sound:
                                    special_sound.play()
                            else:
                                score += 10
                                if hit_sound:
                                    hit_sound.play()
                    
                    if not hit_any and game_active:
                        # 빈 공간 클릭
                        if miss_sound:
                            miss_sound.play()
        
        # 게임 업데이트
        if game_active:
            elapsed_time = current_time - start_time
            remaining_time = max(0, game_duration - elapsed_time)
            
            # 게임 종료 체크
            if remaining_time <= 0:
                game_active = False
            
            # 두더지 업데이트
            for mole in moles:
                mole.update(current_time)
            
            # 무작위로 두더지 등장시키기
            if random.random() < 0.03 + (elapsed_time / game_duration) * 0.07:  # 시간이 지날수록 확률 증가
                hidden_moles = [m for m in moles if not m.is_visible]
                if hidden_moles:
                    mole = random.choice(hidden_moles)
                    mole.is_special = random.random() < 0.2  # 20% 확률로 황금 두더지
                    show_duration = random.uniform(0.5, 2.0 - (elapsed_time / game_duration) * 0.5)  # 시간이 지날수록 짧아짐
                    mole.show(current_time, show_duration)
        
        # 화면 그리기
        screen.blit(background, (0, 0))
        
        # 구멍과 두더지 그리기
        for mole in moles:
            mole.draw(screen)
        
        # 점수 표시
        score_text = font.render(f"점수: {score}", True, BLACK)
        screen.blit(score_text, (20, 20))
        
        if game_active:
            # 남은 시간 표시
            time_text = font.render(f"시간: {int(remaining_time)}초", True, BLACK)
            screen.blit(time_text, (WIDTH - 150, 20))
        else:
            # 시작/종료 메시지
            if start_time == 0:
                message = "클릭하여 게임 시작"
            else:
                message = f"게임 종료! 최종 점수: {score}"
            
            msg_text = large_font.render(message, True, BLACK)
            msg_rect = msg_text.get_rect(center=(WIDTH // 2, HEIGHT // 2))
            screen.blit(msg_text, msg_rect)
        
        pygame.display.flip()
        clock.tick(FPS)

if __name__ == "__main__":
    main()

게임 화면

게임 화면 📸

아래는 게임 실행 화면입니다:

  1. 게임 시작 화면 - "클릭하여 게임 시작" 메시지가 표시됩니다.
  2. 게임 진행 화면 - 3x3 격자의 두더지 구멍, 현재 점수, 남은 시간이 표시됩니다.
  3. 게임 종료 화면 - "게임 종료! 최종 점수: XX" 메시지가 표시됩니다.

화면 구성요소

  1. 배경: 녹색 잔디 배경
  2. 두더지 구멍: 갈색 원형으로 표현
  3. 두더지: 검은색 원형 머리와 흰색 눈, 갈색 코로 구성
  4. 황금 두더지: 금색 원형 머리와 흰색 눈, 코로 구성
  5. 상단 UI: 왼쪽에 점수, 오른쪽에 남은 시간 표시
  6. 메시지: 게임 시작/종료 시 중앙에 표시

코드 설명 📝

1. 게임 초기화 및 설정

# 게임 초기화
pygame.init()
pygame.mixer.init()  # 사운드 시스템 초기화

# 화면 설정
WIDTH, HEIGHT = 800, 600
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("두더지 잡기 게임")

게임을 시작하기 위해 Pygame을 초기화하고, 화면 크기와 제목을 설정합니다. 사운드 시스템도 함께 초기화하여 게임에 효과음을 추가할 수 있게 합니다.

2. 두더지 클래스

두더지 클래스는 게임의 핵심 요소입니다:

class Mole:
    def __init__(self, x, y, size, is_special=False):
        self.x = x
        self.y = y
        self.size = size
        self.is_visible = False
        self.appear_time = 0
        self.hide_time = 0
        self.is_special = is_special
        self.hit = False

각 두더지는 화면상의 위치(x, y), 크기, 보이는지 여부, 등장/사라지는 시간, 특별한 두더지(황금 두더지)인지, 그리고 이미 맞았는지에 대한 상태를 가집니다.

3. 두더지 그리기

def draw(self, surface):
    if self.is_visible:
        # 두더지 구멍 그리기
        pygame.draw.circle(surface, BROWN, (self.x, self.y + self.size//4), self.size//2)
        
        # 두더지 그리기
        if self.is_special:
            color = GOLD  # 황금 두더지
        else:
            color = BLACK  # 일반 두더지
        ...

두더지를 그리는 부분은 원형을 기본으로 하여 눈과 코를 추가해 간단하게 표현했습니다. 특별한 두더지인 경우 금색으로 칠해집니다.

4. 게임 로직

python
복사
# 무작위로 두더지 등장시키기 if random.random() < 0.03 + (elapsed_time / game_duration) * 0.07: # 시간이 지날수록 확률 증가 hidden_moles = [m for m in moles if not m.is_visible] if hidden_moles: mole = random.choice(hidden_moles) mole.is_special = random.random() < 0.2 # 20% 확률로 황금 두더지 show_duration = random.uniform(0.5, 2.0 - (elapsed_time / game_duration) * 0.5) # 시간이 지날수록 짧아짐 mole.show(current_time, show_duration)

두더지가 등장할 확률은 시간이 지날수록 증가하며, 20%의 확률로 황금 두더지가 등장합니다. 또한 두더지가 보이는 시간은 게임이 진행될수록 짧아지므로 점점 더 어려워집니다.

5. 마우스 클릭 처리

# 무작위로 두더지 등장시키기
if random.random() < 0.03 + (elapsed_time / game_duration) * 0.07:  # 시간이 지날수록 확률 증가
    hidden_moles = [m for m in moles if not m.is_visible]
    if hidden_moles:
        mole = random.choice(hidden_moles)
        mole.is_special = random.random() < 0.2  # 20% 확률로 황금 두더지
        show_duration = random.uniform(0.5, 2.0 - (elapsed_time / game_duration) * 0.5)  # 시간이 지날수록 짧아짐
        mole.show(current_time, show_duration)

마우스 클릭 시 두더지에 맞았는지 확인하고, 맞았다면 두더지 종류에 따라 점수를 부여하고 효과음을 재생합니다.

게임 실행 방법 🚀

  1. 필요한 라이브러리 설치:
    pip install pygame
  2. 효과음 파일 준비 (선택 사항):
    • hit.wav: 두더지 타격 시 재생
    • miss.wav: 빈 공간 클릭 시 재생
    • special.wav: 황금 두더지 타격 시 재생
  3. 코드를 whack_a_mole.py 파일로 저장 후 실행:
    python whack_a_mole.py
  4. 게임 화면에서 마우스를 클릭하여 게임을 시작하고, 두더지를 클릭하여 점수를 획득하세요!

게임에서 사용된 프로그래밍 개념 📚

  1. 객체지향 프로그래밍 (OOP): Mole 클래스를 통해 두더지의 속성과 동작을 캡슐화
  2. 이벤트 처리: pygame 이벤트 루프를 사용하여 마우스 클릭 및 게임 종료 처리
  3. 랜덤 함수: random 모듈을 사용하여 두더지의 등장 위치와 시간 결정
  4. 시간 기반 게임 로직: 시간에 따라 변화하는 게임 난이도와 지속 시간 관리
  5. 충돌 감지: 마우스 클릭 위치와 두더지 사이의 거리 계산을 통한 충돌 감지
  6. 그래픽 렌더링: Pygame의 그래픽 기능을 사용한 게임 화면 구성
  7. 상태 관리: 게임의 시작, 진행, 종료 상태를 관리하는 로직

알고리즘 설명 🧮

두더지 등장 알고리즘

if random.random() < 0.03 + (elapsed_time / game_duration) * 0.07:

이 알고리즘은 기본 확률 3%에서 시작하여 게임 진행에 따라 최대 10%까지 확률이 증가합니다. 예를 들어:

  • 게임 시작 시: 3% 확률
  • 게임 중반(30초): 약 6.5% 확률
  • 게임 종료 직전: 10% 확률

이러한 점진적인 난이도 증가는 게임의 재미와 도전성을 높입니다.

두더지 표시 시간 알고리즘

show_duration = random.uniform(0.5, 2.0 - (elapsed_time / game_duration) * 0.5)

이 알고리즘은 시간이 지날수록 두더지가 화면에 표시되는 시간을 짧게 만듭니다:

  • 게임 시작 시: 0.5~2.0초
  • 게임 중반(30초): 0.5~1.75초
  • 게임 종료 직전: 0.5~1.5초

이를 통해 게임이 진행될수록 점점 더 빠른 반응 속도가 필요해지는 도전적인 게임플레이를 제공합니다.

다음 포스팅 예고 🔮

다음 포스팅에서는 '파이썬으로 만드는 미로 탈출 게임(Maze Runner)'에 대해 알아보겠습니다. 미로 생성 알고리즘을 활용하여 매번 다른 미로를 생성하고, 플레이어가 이를 탈출하는 게임을 Pygame으로 구현해볼 예정입니다. 랜덤 미로 생성, 플레이어 이동 메커니즘, 시간제한 시스템, 아이템 수집, 함정 설치 등 게임의 핵심 요소들을 구현하는 방법을 살펴보겠습니다. 또한 미로 난이도 조절, 포그 오브 워(Fog of War) 효과, 그리고 미니맵 기능을 통해 게임에 전략적 요소와 긴장감을 더하는 방법도 함께 배워볼 계획입니다.

여러분의 의견과 질문은 언제나 환영합니다. 행복한 코딩 되세요! 🐍🎮✨

반응형