본문 바로가기

[Pygame] 🏰 2D 타워 디펜스 게임 만들기 5강 | HP 구성 & UI 표시

@도마22026. 2. 5. 19:00
728x90


이번 5강에서는 타워디펜스의 기본 규칙을 추가합니다.

  • 베이스 HP(목숨) 을 만들고
  • 적이 끝까지 도달하면 HP가 감소하며
  • 현재 HP를 화면(UI)로 표시합니다.

1. 베이스 HP 변수 만들기

게임 시작 시 베이스 HP를 하나 정해둡니다.

base_hp = 20

2. 적이 도착하면 HP 감소시키기

이전 강의에서는 reached_end=True인 적을 리스트에서 삭제만 했습니다.
이번 강의에서는 삭제하기 전에 HP 감소 처리를 먼저 해줍니다.

가장 깔끔한 방법은 “도착한 적 수”를 세는 방식입니다.

arrived = sum(1 for e in enemies if e.reached_end)
base_hp -= arrived
enemies = [e for e in enemies if not e.reached_end]

3. UI(텍스트) 표시하기

Pygame에서 텍스트를 그리려면 font가 필요합니다.

font = pygame.font.SysFont(None, 32)

그리고 메인 루프에서 텍스트를 렌더링해서 화면에 붙입니다.

hp_text = font.render(f"HP: {base_hp}", True, (255, 255, 255))
screen.blit(hp_text, (10, 10))

4. 게임 오버 처리

HP가 0 이하가 되면 게임 오버 문구를 띄우고, 스폰을 멈춥니다.

game_over = base_hp <= 0

game_over일 때는 적 스폰과 업데이트를 중단하고, 안내 문구만 출력합니다.


5. 실행 결과


전체 코드

더보기
import pygame
import sys

pygame.init()

SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
pygame.display.set_caption("Tower Defense")

clock = pygame.time.Clock()
FPS = 60

# -----------------------------
# 경로 좌표
# -----------------------------
path_points = [
    (0, 300),
    (100, 300),
    (100, 100),
    (300, 100),
    (300, 500),
    (650, 500),
    (650, 300),
    (450, 300),
    (450, 100),
    (700, 100),
    (700, 200),
    (800, 200)
]

# -----------------------------
# Enemy 클래스
# -----------------------------
class Enemy:
    def __init__(self, path_points, speed=2):
        self.path_points = path_points
        self.speed = speed
        self.x, self.y = path_points[0]
        self.target_index = 1
        self.radius = 12
        self.reached_end = False  # 도착 여부

    def update(self):
        if self.reached_end:
            return

        if self.target_index >= len(self.path_points):
            self.reached_end = True
            return

        tx, ty = self.path_points[self.target_index]
        dx = tx - self.x
        dy = ty - self.y

        dist = (dx * dx + dy * dy) ** 0.5
        if dist == 0:
            self.target_index += 1
            return

        self.x += (dx / dist) * self.speed
        self.y += (dy / dist) * self.speed

        if dist <= self.speed:
            self.x, self.y = tx, ty
            self.target_index += 1
            if self.target_index >= len(self.path_points):
                self.reached_end = True

    def draw(self, screen):
        pygame.draw.circle(screen, (220, 80, 80), (int(self.x), int(self.y)), self.radius)

enemies = []

spawn_interval = 1000  # ms
last_spawn_time = 0

base_hp = 20
font = pygame.font.SysFont(None, 32)

while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()

    game_over = base_hp <= 0

    if not game_over:
        now = pygame.time.get_ticks()
        if now - last_spawn_time >= spawn_interval:
            enemies.append(Enemy(path_points, speed=2))
            last_spawn_time = now

        for enemy in enemies:
            enemy.update()

        arrived = sum(1 for e in enemies if e.reached_end)
        if arrived > 0:
            base_hp -= arrived

        enemies = [e for e in enemies if not e.reached_end]

    screen.fill((30, 30, 30))
    pygame.draw.lines(screen, (200, 180, 100), False, path_points, 40)

    for enemy in enemies:
        enemy.draw(screen)

    hp_text = font.render(f"HP: {base_hp}", True, (255, 255, 255))
    screen.blit(hp_text, (10, 10))

    if game_over:
        over_text = font.render("GAME OVER", True, (255, 255, 255))
        screen.blit(over_text, (SCREEN_WIDTH // 2 - over_text.get_width() // 2, SCREEN_HEIGHT // 2))

    pygame.display.update()
    clock.tick(FPS)

728x90
도마2
@도마2 :: 도마의 코드노트

초보자를 위한 코딩 강의를 정리합니다. 파이썬부터 C#, Unity 게임 제작까지 차근차근 기록합니다. — 도마

목차