본문 바로가기

[Pygame] 🐍 스네이크 게임 만들기 9강 | 게임 오버 화면 + R키로 재시작

@도마22026. 1. 9. 19:00
728x90


9강에서 할 일

9강에서는 “완성된 게임” 느낌을 위해 마무리를 합니다.

  • 벽/몸 충돌 시 프로그램 종료 대신 게임 오버 화면을 띄웁니다
  • 게임 오버 화면에 점수를 표시합니다
  • R 키를 누르면 게임이 처음 상태로 재시작됩니다
  • ESC 키를 누르면 종료됩니다

1) “게임 진행 중 / 게임 오버” 상태를 나눕니다

지금까지는 충돌하면 sys.exit()로 바로 종료했습니다.
이제는 종료하지 않고, 게임 상태를 바꿉니다.

게임 상태 변수 game_over를 만듭니다.

game_over = False

이 변수는 다음처럼 쓰입니다.

  • False면 게임 진행 중입니다
  • True면 게임 오버 화면을 보여줍니다

2) 재시작을 쉽게 하기 위해 초기화 함수를 만듭니다

재시작은 “초기 상태로 되돌리는 작업”입니다.
점수, 뱀, 방향, 먹이를 한 번에 초기화하는 함수가 있으면 편합니다.

다음 함수를 추가합니다.

def reset_game():
    snake = [(5, 5)]
    direction = "RIGHT"
    next_direction = "RIGHT"
    score = 0
    food_x, food_y = spawn_food(snake)
    return snake, direction, next_direction, score, food_x, food_y

이렇게 하면 R키를 누를 때도 그대로 재사용합니다.


3) 게임 시작 시에도 reset_game()으로 초기화합니다

아래처럼 초기화 코드를 교체합니다.

snake, direction, next_direction, score, food_x, food_y = reset_game()
game_over = False

이제 “게임의 시작 상태”가 함수로 정리됩니다.


4) 게임 오버 상태에서 입력 처리합니다

게임 오버일 때는 이동이나 먹이 판정이 필요 없습니다.
대신 입력만 받으면 됩니다.

  • R 키: 재시작
  • ESC 키: 종료

이벤트 처리 부분에 다음을 넣습니다.

if event.type == pygame.KEYDOWN:
    if game_over:
        if event.key == pygame.K_r:
            snake, direction, next_direction, score, food_x, food_y = reset_game()
            game_over = False
        elif event.key == pygame.K_ESCAPE:
            pygame.quit()
            sys.exit()
    else:
        # 게임 진행 중일 때만 방향키 처리
        ...

이렇게 하면 게임 오버 상태에서는 방향키가 먹히지 않습니다.


5) 충돌 시 종료 대신 game_over = True로 바꿉니다

8강에서 충돌하면 종료했었습니다.
이 부분을 다음처럼 바꿉니다.

  • 벽 충돌 → game_over = True
  • 몸 충돌 → game_over = True
game_over = True

그리고 게임 오버가 되면 더 이상 이동 로직이 실행되지 않도록
이동 블록을 if not game_over:로 감쌉니다.


6) 게임 오버 화면을 그립니다

게임 오버일 때는 화면 중앙에 메시지를 띄웁니다.

  • “GAME OVER”
  • “Score: n”
  • “Press R to Restart / ESC to Quit”

텍스트는 폰트를 하나 더 만들어서 크게 표시합니다.

big_font = pygame.font.SysFont(None, 60)

그리고 game_over일 때 그립니다.


9강 정리

이번 강의에서 만든 기능입니다.

  • 게임이 종료되지 않고 게임 오버 화면이 뜹니다
  • 점수를 보여줍니다
  • R키로 재시작합니다
  • ESC로 종료합니다

이제 “완성된 스네이크 게임”입니다.


전체 코드

더보기
import pygame
import sys
import random

pygame.init()

# =========================
# 기본 설정
# =========================
CELL_SIZE = 40
GRID_SIZE = 10
SCREEN_SIZE = CELL_SIZE * GRID_SIZE

BLACK = (0, 0, 0)
GREEN = (0, 255, 0)
YELLOW = (255, 255, 0)
WHITE = (255, 255, 255)

# =========================
# 화면 설정
# =========================
screen = pygame.display.set_mode((SCREEN_SIZE, SCREEN_SIZE))
pygame.display.set_caption("10x10 Snake Game")

clock = pygame.time.Clock()

# =========================
# 폰트
# =========================
font = pygame.font.SysFont(None, 36)
big_font = pygame.font.SysFont(None, 60)

# =========================
# 먹이 생성 함수 (몸 전체와 겹침 방지)
# =========================
def spawn_food(snake):
    while True:
        x = random.randint(0, GRID_SIZE - 1)
        y = random.randint(0, GRID_SIZE - 1)
        if (x, y) not in snake:
            return x, y

# =========================
# 게임 초기화 함수 (재시작용)
# =========================
def reset_game():
    snake = [(5, 5)]
    direction = "RIGHT"
    next_direction = "RIGHT"
    score = 0
    food_x, food_y = spawn_food(snake)
    return snake, direction, next_direction, score, food_x, food_y

snake, direction, next_direction, score, food_x, food_y = reset_game()
game_over = False

# =========================
# 게임 루프
# =========================
while True:
    # 이벤트 처리
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()

        if event.type == pygame.KEYDOWN:
            # 게임 오버 상태 입력
            if game_over:
                if event.key == pygame.K_r:
                    snake, direction, next_direction, score, food_x, food_y = reset_game()
                    game_over = False
                elif event.key == pygame.K_ESCAPE:
                    pygame.quit()
                    sys.exit()
            else:
                # 게임 진행 중 방향키 입력
                if event.key == pygame.K_UP and direction != "DOWN":
                    next_direction = "UP"
                elif event.key == pygame.K_DOWN and direction != "UP":
                    next_direction = "DOWN"
                elif event.key == pygame.K_LEFT and direction != "RIGHT":
                    next_direction = "LEFT"
                elif event.key == pygame.K_RIGHT and direction != "LEFT":
                    next_direction = "RIGHT"

    # 이동 및 판정 (게임 진행 중일 때만)
    if not game_over:
        direction = next_direction
        head_x, head_y = snake[0]

        if direction == "UP":
            new_head = (head_x, head_y - 1)
        elif direction == "DOWN":
            new_head = (head_x, head_y + 1)
        elif direction == "LEFT":
            new_head = (head_x - 1, head_y)
        else:  # RIGHT
            new_head = (head_x + 1, head_y)

        # 벽 충돌
        if (
            new_head[0] < 0 or new_head[0] >= GRID_SIZE or
            new_head[1] < 0 or new_head[1] >= GRID_SIZE
        ):
            game_over = True
        # 자기 몸 충돌
        elif new_head in snake[1:]:
            game_over = True
        else:
            # 머리 추가
            snake.insert(0, new_head)

            # 먹이 먹기
            if new_head[0] == food_x and new_head[1] == food_y:
                score += 1
                food_x, food_y = spawn_food(snake)
            else:
                snake.pop()

    # =========================
    # 그리기
    # =========================
    screen.fill(BLACK)

    # 점수 표시
    score_text = font.render(f"Score: {score}", True, WHITE)
    screen.blit(score_text, (10, 10))

    # 뱀 그리기
    for x, y in snake:
        rect = pygame.Rect(x * CELL_SIZE, y * CELL_SIZE, CELL_SIZE, CELL_SIZE)
        pygame.draw.rect(screen, GREEN, rect)

    # 먹이 그리기
    food_rect = pygame.Rect(
        food_x * CELL_SIZE,
        food_y * CELL_SIZE,
        CELL_SIZE,
        CELL_SIZE
    )
    pygame.draw.rect(screen, YELLOW, food_rect)

    # 게임 오버 화면
    if game_over:
        over_text = big_font.render("GAME OVER", True, WHITE)
        info_text = font.render(f"Score: {score}", True, WHITE)
        restart_text = font.render("Press R to Restart / ESC to Quit", True, WHITE)

        over_rect = over_text.get_rect(center=(SCREEN_SIZE // 2, SCREEN_SIZE // 2 - 40))
        info_rect = info_text.get_rect(center=(SCREEN_SIZE // 2, SCREEN_SIZE // 2 + 10))
        restart_rect = restart_text.get_rect(center=(SCREEN_SIZE // 2, SCREEN_SIZE // 2 + 50))

        screen.blit(over_text, over_rect)
        screen.blit(info_text, info_rect)
        screen.blit(restart_text, restart_rect)

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

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

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

목차