티스토리 뷰

추가 기능 구현

프롬프트 (step05.py에 이어서 작성)

40개의 벽돌 중 랜덤하게 4개의 벽돌을 보너스 벽돌로 지정하여라.
보너스 벽돌은 일반 벽돌과 다른 색으로 표시하여라.
일반 벽돌은 10점, 보너스 벽돌은 20점을 주도록 수정하여라.

단계별 핵심 설명

1. 전역변수

이번 실습에서는 보너스 벽돌을 만들기 위하여 random 라이브러리를 추가하였다.

import random
 

그리고 보너스 벽돌과 점수 정보를 전역변수로 추가하였다.

BONUS_BRICK_COUNT = 4
NORMAL_SCORE = 10
BONUS_SCORE = 20
bonus_bricks = []
 
  • BONUS_BRICK_COUNT는 보너스 벽돌의 개수이다.
  • NORMAL_SCORE는 일반 벽돌 점수이다
  • BONUS_SCORE는 보너스 벽돌 점수이다.
  • bonus_bricks는 랜덤하게 선택된 보너스 벽돌을 저장하는 리스트이다.

보너스 벽돌을 다른 색으로 표시하기 위하여 RED 색상도 추가하였다.

RED = (255, 0, 0)

2. 초기화

벽돌 40개를 모두 만든 뒤, 그중에서 랜덤하게 4개를 선택한다.

bonus_bricks = random.sample(bricks, BONUS_BRICK_COUNT)
 
  • random.sample()은 리스트 안에서 중복 없이 원하는 개수만큼 뽑을 때 사용한다.
  • 여기서는 bricks 리스트 안에 들어 있는 40개의 벽돌 중에서 4개를 랜덤하게 선택하여 bonus_bricks에 저장한다.
  • 즉, 실행할 때마다 보너스 벽돌의 위치가 달라진다.

3. 입력

입력 단계는 기존 STEP05와 거의 같다. 이번 실습에서는 보너스 벽돌을 만드는 것이 목적이므로 입력 처리에는 큰 변화가 없다.

기존처럼 "ready" 상태에서 Space Bar를 누르면 게임이 시작된다.

if game_state == "ready":
    if event.key == pygame.K_SPACE:
        game_state = "play"
패들 이동도 기존처럼 "play" 상태에서만 가능하다. 

4. 업데이트

업데이트 단계에서 가장 중요한 변화는 벽돌과 충돌했을 때의 점수 처리이다. 먼저 공이 충돌한 벽돌이 보너스 벽돌인지 확인한다.

is_bonus = brick in bonus_bricks
 
  • 충돌한 벽돌이 bonus_bricks 안에 있으면 보너스 벽돌이다.
  • 보너스 벽돌이면 20점을 더한다.
if is_bonus:
    bonus_bricks.remove(brick)
    score += BONUS_SCORE
 
  • 일반 벽돌이면 10점을 더한다.
else:
    score += NORMAL_SCORE
  • 따라서 점수 규칙은 다음과 같다.
일반 벽돌   → 10점
보너스 벽돌 → 20점

5. 출력

출력 단계에서는 벽돌을 그릴 때 보너스 벽돌인지 확인한다.

for brick in bricks:
    if brick in bonus_bricks:
        pygame.draw.rect(screen, RED, brick)
    else:
        pygame.draw.rect(screen, WHITE, brick)
 
  • 보너스 벽돌이면 빨간색으로 출력한다.
pygame.draw.rect(screen, RED, brick)
  • 일반 벽돌이면 기존처럼 흰색으로 출력한다.
pygame.draw.rect(screen, WHITE, brick)
 
  • 따라서 화면에는 흰색 벽돌 36개와 빨간색 보너스 벽돌 4개가 표시된다.

6. 실행

실행 단계는 기존 STEP05와 같다.
다만 게임을 실행할 때마다 init() 함수 안에서 보너스 벽돌을 새로 랜덤 선택하므로, 매번 다른 위치의 벽돌 4개가 보너스 벽돌이 된다.


전체코드 (step06.py)

import pygame
import sys
import random  # ADDED 랜덤 보너스 벽돌 선택을 위해 추가


# 전역 변수
WIDTH, HEIGHT = 600, 800
screen = None
clock = None
running = True

# 게임 상태
game_state = "ready"  # ready, play, game_over, clear

# 종료 메시지
end_message = ""

# 색상
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
RED = (255, 0, 0)  # ADDED 보너스 벽돌 색상

# 글꼴 정보
font = None

# 공 정보
BALL_RADIUS = 10
BALL_SPEED_X = 4
BALL_SPEED_Y = -4
ball_pos = None
ball_vel = None

# 패들 정보
PADDLE_WIDTH = 100
PADDLE_HEIGHT = 15
PADDLE_SPEED = 7
paddle_rect = None
paddle_dx = 0

# 벽돌 정보
BRICK_ROWS = 5
BRICK_COLS = 8
BRICK_WIDTH = 60
BRICK_HEIGHT = 20
BRICK_GAP = 10
bricks = []

# ADDED 보너스 벽돌 정보
BONUS_BRICK_COUNT = 4
NORMAL_SCORE = 10
BONUS_SCORE = 20
bonus_bricks = []

# 게임 정보
score = 0
life = 3
block_count = 0


# 1. 게임 초기화
def init():
    global screen, clock
    global font
    global ball_pos, ball_vel, paddle_rect, bricks
    global score, life, block_count
    global game_state, end_message
    global bonus_bricks  # ADDED

    pygame.init()
    screen = pygame.display.set_mode((WIDTH, HEIGHT))
    pygame.display.set_caption("벽돌깨기 5단계 - 보너스 벽돌")
    clock = pygame.time.Clock()

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

    # 게임 상태 초기화
    game_state = "ready"
    end_message = ""

    # 게임 정보 초기화
    score = 0
    life = 3
    block_count = BRICK_ROWS * BRICK_COLS

    # 공 초기 위치와 속도
    ball_pos = [WIDTH // 2, HEIGHT // 2]
    ball_vel = [BALL_SPEED_X, BALL_SPEED_Y]

    # 패들 초기 위치
    paddle_x = WIDTH // 2 - PADDLE_WIDTH // 2
    paddle_y = HEIGHT - 50

    paddle_rect = pygame.Rect(
        paddle_x,
        paddle_y,
        PADDLE_WIDTH,
        PADDLE_HEIGHT
    )

    # 벽돌 생성
    bricks = []

    total_brick_width = BRICK_COLS * BRICK_WIDTH + (BRICK_COLS - 1) * BRICK_GAP
    start_x = WIDTH // 2 - total_brick_width // 2
    start_y = 80

    for row in range(BRICK_ROWS):
        for col in range(BRICK_COLS):
            brick_x = start_x + col * (BRICK_WIDTH + BRICK_GAP)
            brick_y = start_y + row * (BRICK_HEIGHT + BRICK_GAP)

            brick = pygame.Rect(
                brick_x,
                brick_y,
                BRICK_WIDTH,
                BRICK_HEIGHT
            )

            bricks.append(brick)

    # ADDED 전체 벽돌 중 랜덤하게 4개를 보너스 벽돌로 선택
    bonus_bricks = random.sample(bricks, BONUS_BRICK_COUNT)


# 2. 입력 처리
def handle_input():
    global running
    global paddle_dx
    global game_state

    paddle_dx = 0

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False

        # ready 상태에서 SPACE BAR를 누르면 게임 시작
        if event.type == pygame.KEYDOWN:
            if game_state == "ready":
                if event.key == pygame.K_SPACE:
                    game_state = "play"

            # 게임 종료 상태에서 아무 키나 누르면 종료
            elif game_state == "game_over" or game_state == "clear":
                running = False

    # play 상태에서만 패들 이동
    if game_state == "play":
        keys = pygame.key.get_pressed()

        if keys[pygame.K_LEFT]:
            paddle_dx = -PADDLE_SPEED

        if keys[pygame.K_RIGHT]:
            paddle_dx = PADDLE_SPEED


# 3. 게임 업데이트
def update_game():
    global ball_pos, ball_vel, bricks
    global score, life, block_count
    global game_state, end_message
    global bonus_bricks  # ADDED

    # play 상태가 아니면 게임을 업데이트하지 않음
    if game_state != "play":
        return

    # 패들 위치 업데이트
    paddle_rect.x += paddle_dx

    # 패들이 화면 밖으로 나가지 않도록 제한
    if paddle_rect.left < 0:
        paddle_rect.left = 0

    if paddle_rect.right > WIDTH:
        paddle_rect.right = WIDTH

    # 공 위치 업데이트
    ball_pos[0] += ball_vel[0]
    ball_pos[1] += ball_vel[1]

    # 공을 충돌 검사용 사각형으로 변환
    ball_rect = pygame.Rect(
        ball_pos[0] - BALL_RADIUS,
        ball_pos[1] - BALL_RADIUS,
        BALL_RADIUS * 2,
        BALL_RADIUS * 2
    )

    # 왼쪽 벽 충돌
    if ball_pos[0] - BALL_RADIUS <= 0:
        ball_vel[0] = abs(ball_vel[0])

    # 오른쪽 벽 충돌
    if ball_pos[0] + BALL_RADIUS >= WIDTH:
        ball_vel[0] = -abs(ball_vel[0])

    # 위쪽 벽 충돌
    if ball_pos[1] - BALL_RADIUS <= 0:
        ball_vel[1] = abs(ball_vel[1])

    # 패들과 충돌
    if ball_rect.colliderect(paddle_rect):
        if ball_vel[1] > 0:
            ball_vel[1] = -abs(ball_vel[1])
            ball_pos[1] = paddle_rect.top - BALL_RADIUS

    # 벽돌과 충돌
    for brick in bricks[:]:
        if ball_rect.colliderect(brick):

            # ADDED 충돌한 벽돌이 보너스 벽돌인지 먼저 확인
            is_bonus = brick in bonus_bricks

            bricks.remove(brick)

            # ADDED 보너스 벽돌이면 보너스 목록에서도 제거
            if is_bonus:
                bonus_bricks.remove(brick)
                score += BONUS_SCORE
            else:
                score += NORMAL_SCORE

            ball_vel[1] *= -1
            block_count -= 1

            # 남은 벽돌 수가 0이면 게임 클리어
            if block_count <= 0:
                game_state = "clear"
                end_message = "You Win"
                return

            break

    # 공이 화면 아래로 떨어졌을 때
    if ball_pos[1] - BALL_RADIUS > HEIGHT:
        life -= 1

        # 생명이 0이면 게임 오버
        if life <= 0:
            game_state = "game_over"
            end_message = "Game Over"
            return

        # 생명이 남아 있으면 공을 중앙으로 되돌리고 ready 상태로 변경
        ball_pos = [WIDTH // 2, HEIGHT // 2]
        ball_vel = [BALL_SPEED_X, BALL_SPEED_Y]
        game_state = "ready"


# 종료 화면 출력
def render_end_screen():
    screen.fill(BLACK)

    message_text = font.render(end_message, True, WHITE)
    message_rect = message_text.get_rect(
        center=(WIDTH // 2, HEIGHT // 2 - 30)
    )
    screen.blit(message_text, message_rect)

    guide_text = font.render("Press any key to exit", True, WHITE)
    guide_rect = guide_text.get_rect(
        center=(WIDTH // 2, HEIGHT // 2 + 20)
    )
    screen.blit(guide_text, guide_rect)


# 4. 출력 처리
def render():
    # 게임 종료 상태이면 종료 화면 출력
    if game_state == "game_over" or game_state == "clear":
        render_end_screen()
        pygame.display.flip()
        return

    screen.fill(BLACK)

    # 게임 정보 출력
    text_score = font.render(f"Score: {score}", True, WHITE)
    text_life = font.render(f"Life: {life}", True, WHITE)
    text_blocks = font.render(f"Blocks: {block_count}", True, WHITE)

    score_rect = text_score.get_rect(topleft=(10, 10))
    life_rect = text_life.get_rect(midtop=(WIDTH // 2, 10))
    blocks_rect = text_blocks.get_rect(topright=(WIDTH - 10, 10))

    screen.blit(text_score, score_rect)
    screen.blit(text_life, life_rect)
    screen.blit(text_blocks, blocks_rect)

    # CHANGED 벽돌 그리기
    for brick in bricks:
        if brick in bonus_bricks:
            pygame.draw.rect(screen, RED, brick)
        else:
            pygame.draw.rect(screen, WHITE, brick)

    # 공 그리기
    pygame.draw.circle(
        screen,
        WHITE,
        (int(ball_pos[0]), int(ball_pos[1])),
        BALL_RADIUS
    )

    # 패들 그리기
    pygame.draw.rect(screen, WHITE, paddle_rect)

    # ready 상태에서 시작 안내 문구 출력
    if game_state == "ready":
        start_text = font.render("Press SPACE to Start", True, WHITE)
        start_rect = start_text.get_rect(
            center=(WIDTH // 2, HEIGHT // 2 + 60)
        )
        screen.blit(start_text, start_rect)

    pygame.display.flip()


# 5. 게임 실행
def run_game():
    init()

    while running:
        handle_input()
        update_game()
        render()
        clock.tick(60)

    pygame.quit()
    sys.exit()


run_game()

 

반응형
반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2026/06   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
글 보관함