본문 바로가기

[Pygame] 🧱 벽돌 깨기 게임 만들기 7강 | 공과 벽돌 충돌

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


공과 벽돌 충돌

이번 강의에서는 공이 벽돌과 충돌했을 때 벽돌이 사라지도록 처리합니다.
이 단계부터 게임에 명확한 목표와 진행이 생기기 시작합니다.

이번 강의의 핵심은 다음과 같습니다.

  • 공과 벽돌의 충돌을 감지합니다
  • 충돌한 벽돌을 제거합니다
  • 충돌 시 공의 이동 방향을 변경합니다

공과 벽돌 충돌의 기본 개념

현재 게임에는 여러 개의 벽돌이 리스트로 관리되고 있습니다.
공은 매 프레임 이동하면서 이 벽돌들 중 하나와 충돌할 수 있습니다.

충돌 처리의 기본 흐름은 다음과 같습니다.

  • 모든 벽돌을 하나씩 검사합니다
  • 공과 벽돌이 충돌했는지 확인합니다
  • 충돌했다면 해당 벽돌을 제거합니다

벽돌 리스트를 순회하며 충돌 검사하기

먼저 벽돌 리스트를 반복문으로 순회하면서
공과 충돌했는지 확인합니다.

for brick in bricks:
    if ball_rect.colliderect(brick):
        bricks.remove(brick)
        ball_speed_y *= -1
        break

이 코드는
공이 어떤 벽돌과 충돌했는지를 검사하고,
충돌한 벽돌을 리스트에서 제거합니다.


break가 필요한 이유

벽돌을 제거한 뒤 break를 사용하는 이유는 중요합니다.

  • 한 프레임에 여러 벽돌을 동시에 제거하지 않기 위함입니다
  • 리스트를 순회하면서 요소를 제거할 때 발생할 수 있는 오류를 방지합니다

벽돌깨기 게임에서는
한 번의 충돌에 하나의 벽돌만 제거하는 것이 자연스럽습니다.


충돌 시 공의 방향 변경

이번 강의에서는
충돌 방향을 단순하게 처리합니다.

ball_speed_y *= -1

즉, 벽돌에 맞으면
공이 위로 가고 있었다면 아래로,
아래로 가고 있었다면 위로 이동하게 됩니다.

다음 강의에서는
이 단순한 처리 방식을 개선하여
정확한 충돌 방향 계산을 구현합니다.


충돌 처리 위치의 중요성

공과 벽돌의 충돌 처리는
다음 위치에서 수행해야 합니다.

  • 공 이동 이후
  • Rect 위치 갱신 이후
  • 화면에 그리기 이전

이 순서를 지켜야
충돌이 안정적으로 처리됩니다.


현재 단계의 결과

이번 강의까지 구현된 결과는 다음과 같습니다.

  • 공이 벽과 패들에 튕깁니다
  • 공이 벽돌에 닿으면 벽돌이 사라집니다
  • 공을 계속 튕기며 벽돌을 제거할 수 있습니다

이제 벽돌깨기 게임은
실제로 플레이 가능한 상태가 되었습니다.

다음 강의에서는
벽돌의 어느 면에 맞았는지를 계산하여
공의 반사 방향을 더 정확하게 처리합니다.



전체 코드

더보기
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("Breakout Game")

# 색상
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)

# FPS 설정
clock = pygame.time.Clock()
FPS = 60

# 패들 설정
paddle_width = 100
paddle_height = 15
paddle_speed = 7

paddle_x = (SCREEN_WIDTH - paddle_width) // 2
paddle_y = SCREEN_HEIGHT - 40

paddle_rect = pygame.Rect(
    paddle_x,
    paddle_y,
    paddle_width,
    paddle_height
)

# 공 설정
ball_radius = 8
ball_x = SCREEN_WIDTH // 2
ball_y = SCREEN_HEIGHT // 2

ball_speed_x = 5
ball_speed_y = -5

ball_rect = pygame.Rect(
    ball_x - ball_radius,
    ball_y - ball_radius,
    ball_radius * 2,
    ball_radius * 2
)

# 벽돌 설정
brick_width = 60
brick_height = 20
brick_padding = 10

rows = 4
cols = 10

bricks = []

for row in range(rows):
    for col in range(cols):
        brick_x = col * (brick_width + brick_padding) + 35
        brick_y = row * (brick_height + brick_padding) + 50

        brick_rect = pygame.Rect(
            brick_x,
            brick_y,
            brick_width,
            brick_height
        )

        bricks.append(brick_rect)

# 게임 루프
running = True
while running:
    clock.tick(FPS)

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

    # 패들 입력 처리
    keys = pygame.key.get_pressed()
    if keys[pygame.K_LEFT]:
        paddle_rect.x -= paddle_speed
    if keys[pygame.K_RIGHT]:
        paddle_rect.x += paddle_speed

    if paddle_rect.left < 0:
        paddle_rect.left = 0
    if paddle_rect.right > SCREEN_WIDTH:
        paddle_rect.right = SCREEN_WIDTH

    # 공 이동
    ball_x += ball_speed_x
    ball_y += ball_speed_y

    ball_rect.x = ball_x - ball_radius
    ball_rect.y = ball_y - ball_radius

    # 벽 충돌 처리
    if ball_rect.left <= 0 or ball_rect.right >= SCREEN_WIDTH:
        ball_speed_x *= -1
    if ball_rect.top <= 0:
        ball_speed_y *= -1

    # 패들 충돌 처리
    if ball_rect.colliderect(paddle_rect):
        ball_speed_y *= -1
        ball_rect.bottom = paddle_rect.top
        ball_y = ball_rect.centery

    # 벽돌 충돌 처리
    for brick in bricks:
        if ball_rect.colliderect(brick):
            bricks.remove(brick)
            ball_speed_y *= -1
            break

    # 화면 그리기
    screen.fill(BLACK)
    pygame.draw.rect(screen, WHITE, paddle_rect)
    pygame.draw.circle(screen, WHITE, (ball_x, ball_y), ball_radius)

    for brick in bricks:
        pygame.draw.rect(screen, WHITE, brick)

    pygame.display.flip()

pygame.quit()
sys.exit()

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

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

목차