
이펙트 & 사운드 추가
이번 강의에서는 벽돌깨기 게임에
시각적 이펙트와 사운드 효과를 추가합니다.
이 단계의 목적은
게임의 로직을 더 만드는 것이 아니라,
플레이 감각과 완성도를 크게 끌어올리는 것입니다.
이번 강의가 끝나면
같은 게임이라도 “손에 착 붙는 느낌”이 확실히 달라집니다.
이펙트와 사운드의 역할
이펙트와 사운드는
게임 플레이에 직접적인 규칙 변화를 주지는 않습니다.
하지만 다음 효과를 만들어냅니다.
- 충돌이 명확하게 느껴집니다
- 플레이 결과가 즉각적으로 전달됩니다
- 게임이 훨씬 살아 있는 것처럼 느껴집니다
즉, 게임다움의 완성 단계입니다.
사용할 사운드 파일 준비
이번 강의에서는 다음 사운드를 사용합니다.
- 벽돌 충돌 사운드
- 패들 충돌 사운드
- 아이템 획득 사운드
예시는 다음 파일명을 기준으로 설명합니다.
brick.wav
paddle.wav
item.wav
이 파일들은
파이썬 파일과 같은 폴더에 두는 것을 기준으로 합니다.
사운드 초기화 및 로드
파이게임의 사운드를 사용하기 위해
믹서를 초기화하고 사운드를 로드합니다.
pygame.mixer.init()
brick_sound = pygame.mixer.Sound("brick.wav")
paddle_sound = pygame.mixer.Sound("paddle.wav")
item_sound = pygame.mixer.Sound("item.wav")
이제 코드에서
필요한 순간에 사운드를 재생할 수 있습니다.
패들 충돌 시 사운드 추가
패들과 공이 충돌했을 때
사운드를 재생합니다.
if ball_rect.colliderect(paddle_rect):
ball_speed_y *= -1
ball_rect.bottom = paddle_rect.top
ball_y = ball_rect.centery
paddle_sound.play()
이 사운드는
공을 제대로 받아냈다는 피드백을 줍니다.
벽돌 충돌 시 사운드 추가
벽돌이 깨질 때
사운드를 재생합니다.
brick_sound.play()
이 코드는
벽돌 제거 로직 바로 앞이나 뒤에 추가합니다.
아이템 획득 사운드
아이템을 획득했을 때도
별도의 사운드를 재생합니다.
item_sound.play()
이 사운드는
플레이어에게 “보상을 얻었다”는 느낌을 줍니다.
간단한 충돌 이펙트 구현
복잡한 파티클 대신
짧게 사라지는 사각형 이펙트를 사용합니다.
이펙트 역시 리스트로 관리합니다.
effects = []
이펙트 생성
벽돌이 깨질 때
이펙트를 하나 생성합니다.
effects.append({
"rect": pygame.Rect(brick.x, brick.y, brick.width, brick.height),
"timer": 10
})
timer 값은
이펙트가 유지되는 프레임 수입니다.
이펙트 업데이트와 제거
매 프레임마다
이펙트의 시간을 줄이고 제거합니다.
for effect in effects[:]:
effect["timer"] -= 1
if effect["timer"] <= 0:
effects.remove(effect)
이펙트 그리기
이펙트는 벽돌보다 밝은 색으로
짧게 표시합니다.
for effect in effects:
pygame.draw.rect(screen, (255, 200, 200), effect["rect"])
현재 단계의 결과
이번 강의까지 구현된 결과는 다음과 같습니다.
- 공이 패들에 맞으면 사운드가 재생됩니다
- 벽돌이 깨질 때 사운드와 이펙트가 출력됩니다
- 아이템을 획득하면 효과음이 재생됩니다
이제 게임은
로직 + 감각이 모두 갖춰진 상태가 되었습니다.

예제에 사용된 사운드
전체 코드
import pygame
import sys
import random
pygame.init()
pygame.mixer.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)
GREEN = (0, 200, 0)
EFFECT_COLOR = (255, 200, 200)
clock = pygame.time.Clock()
FPS = 60
font = pygame.font.SysFont(None, 30)
brick_sound = pygame.mixer.Sound("brick.wav")
paddle_sound = pygame.mixer.Sound("paddle.wav")
item_sound = pygame.mixer.Sound("item.wav")
score = 0
lives = 3
paddle_width = 100
paddle_height = 15
paddle_speed = 7
paddle_rect = pygame.Rect(
(SCREEN_WIDTH - paddle_width) // 2,
SCREEN_HEIGHT - 40,
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 = []
items = []
effects = []
item_speed = 4
def create_bricks():
bricks.clear()
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
bricks.append(
pygame.Rect(brick_x, brick_y, brick_width, brick_height)
)
def create_item(x, y):
items.append(pygame.Rect(x, y, 20, 20))
create_bricks()
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
paddle_rect.left = max(paddle_rect.left, 0)
paddle_rect.right = min(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
paddle_sound.play()
for brick in bricks:
if ball_rect.colliderect(brick):
overlap_left = ball_rect.right - brick.left
overlap_right = brick.right - ball_rect.left
overlap_top = ball_rect.bottom - brick.top
overlap_bottom = brick.bottom - ball_rect.top
min_overlap = min(overlap_left, overlap_right, overlap_top, overlap_bottom)
if min_overlap == overlap_left or min_overlap == overlap_right:
ball_speed_x *= -1
else:
ball_speed_y *= -1
if random.random() < 0.3:
create_item(brick.centerx - 10, brick.centery)
effects.append({
"rect": pygame.Rect(brick.x, brick.y, brick.width, brick.height),
"timer": 10
})
brick_sound.play()
bricks.remove(brick)
score += 10
break
for item in items[:]:
item.y += item_speed
if item.colliderect(paddle_rect):
paddle_rect.width += 30
item_sound.play()
items.remove(item)
elif item.top > SCREEN_HEIGHT:
items.remove(item)
for effect in effects[:]:
effect["timer"] -= 1
if effect["timer"] <= 0:
effects.remove(effect)
if ball_rect.top > SCREEN_HEIGHT:
lives -= 1
if lives <= 0:
running = False
else:
ball_x = SCREEN_WIDTH // 2
ball_y = SCREEN_HEIGHT // 2
ball_speed_x = 5
ball_speed_y = -5
paddle_rect.width = paddle_width
paddle_rect.x = (SCREEN_WIDTH - paddle_width) // 2
create_bricks()
items.clear()
effects.clear()
screen.fill(BLACK)
screen.blit(font.render(f"Score: {score}", True, WHITE), (10, 10))
screen.blit(font.render(f"Lives: {lives}", True, WHITE), (SCREEN_WIDTH - 100, 10))
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)
for item in items:
pygame.draw.rect(screen, GREEN, item)
for effect in effects:
pygame.draw.rect(screen, EFFECT_COLOR, effect["rect"])
pygame.display.flip()
pygame.quit()
sys.exit()
'⚙️ Python > 🎮 Pygame 실전' 카테고리의 다른 글
| [Pygame] 🧱 벽돌 깨기 게임 만들기 13강 | 게임 시작 흐름 개선 (0) | 2026.02.26 |
|---|---|
| [Pygame] 🧱 벽돌 깨기 게임 만들기 12강 | 타이틀 화면 추가 (0) | 2026.02.25 |
| [Pygame] 🧱 벽돌 깨기 게임 만들기 10강 | 아이템 추가 (0) | 2026.02.24 |
| [Pygame] 🧱 벽돌 깨기 게임 만들기 9강 | 점수 & 라이프 시스템 (0) | 2026.02.24 |
| [Pygame] 🧱 벽돌 깨기 게임 만들기 8강 | 충돌 방향 정확히 계산하기 (0) | 2026.02.23 |