Menu
CoddyTech

모든 타격에 불꽃 튀기기

Coddy Pygame 여정의 사운드와 게임의 손맛 섹션에 포함된 레슨. 23개 중 21번째.

폭발하는 적은 실제로 폭발하는 느낌이 나야 합니다. 불꽃부터 시작해 보세요. 적이 있던 자리에 입자가 폭발하듯 흩어지게 합니다.

폭발은 두 곳, 레이저에 맞았을 때와 충돌했을 때 발생하므로 폭발 효과를 함수에 넣으세요.

def burst(center):
    for i in range(16):
        particles.append({"x": center[0], "y": center[1],
                          "vx": random.uniform(-4, 4), "vy": random.uniform(-4, 4),
                          "life": random.randint(15, 30)})

이 함수는 불꽃만 생성합니다. 불꽃을 움직이는 일은 매 프레임마다 해야 합니다. Particles 장에서 했던 것처럼 각각의 불꽃을 움직이고, 수명을 줄인 다음, 살아 있는 것만 남기세요.

explosions.update() 옆에서, if lives > 0 ... 바깥에 이 작업을 하세요. 게임을 끝내는 충돌도 폭발을 일으키며, Game over 뒤에도 불꽃이 계속 흩어져야 합니다. 폭발 효과를 그린 다음 불꽃을 그려 불꽃이 위에 표시되도록 하세요.

challenge icon

챌린지

중급
  1. 반복문 앞에 particles = []를 만드세요.
  2. burst(center)를 작성하세요. center 위치에 입자 16개를 만들고, vx와 vy는 random.uniform(-4, 4)에서, life는 random.randint(15, 30)에서 가져옵니다.
  3. 레이저가 적을 파괴하는 곳과 적이 우주선에 부딪히는 곳에서 burst(enemy.rect.center)를 호출하세요.
  4. explosions.update() 옆에서 입자를 이동시키고, 수명을 줄인 다음, 수명이 다한 입자를 제거하세요.
  5. 폭발을 그린 다음, 각 입자를 반지름이 life // 10 + 1인 주황색 (255, 170, 60) 원으로 그리세요.

직접 해보기

import random
import pygame

pygame.init()
screen = pygame.display.set_mode((640, 480))
pygame.display.set_caption("Star Patrol")
clock = pygame.time.Clock()
font = pygame.font.Font(None, 32)

ship_image = pygame.image.load("assets/images/ship.png").convert_alpha()
laser_image = pygame.image.load("assets/images/laser.png").convert_alpha()
red_image = pygame.image.load("assets/images/enemy_red.png").convert_alpha()
green_image = pygame.image.load("assets/images/enemy_green.png").convert_alpha()
yellow_image = pygame.image.load("assets/images/enemy_yellow.png").convert_alpha()
explosion_frames = []
for number in range(1, 5):
    explosion_frames.append(pygame.image.load(f"assets/images/explosion_{number}.png").convert_alpha())

laser_sound = pygame.mixer.Sound("assets/sounds/laser.ogg")
laser_sound.set_volume(0.4)
explosion_sound = pygame.mixer.Sound("assets/sounds/explosion.ogg")
hit_sound = pygame.mixer.Sound("assets/sounds/hit.ogg")

WAVES = [(red_image, 6, 2), (green_image, 8, 2), (yellow_image, 10, 3)]


class Player(pygame.sprite.Sprite):
    def __init__(self):
        super().__init__()
        self.image = ship_image
        self.rect = self.image.get_rect(midbottom=(320, 470))
        self.mask = pygame.mask.from_surface(self.image)

    def update(self):
        keys = pygame.key.get_pressed()
        if keys[pygame.K_LEFT]:
            self.rect.x -= 6
        if keys[pygame.K_RIGHT]:
            self.rect.x += 6
        self.rect.clamp_ip(screen.get_rect())


class Laser(pygame.sprite.Sprite):
    def __init__(self, x, y):
        super().__init__()
        self.image = laser_image
        self.rect = self.image.get_rect(midbottom=(x, y))
        self.mask = pygame.mask.from_surface(self.image)

    def update(self):
        self.rect.y -= 10
        if self.rect.bottom < 0:
            self.kill()


class Enemy(pygame.sprite.Sprite):
    def __init__(self, image, x, y, speed):
        super().__init__()
        self.image = image
        self.rect = self.image.get_rect(center=(x, y))
        self.mask = pygame.mask.from_surface(self.image)
        self.speed = speed

    def update(self):
        self.rect.y += self.speed


class Explosion(pygame.sprite.Sprite):
    def __init__(self, center):
        super().__init__()
        self.index = 0
        self.timer = 0
        self.image = explosion_frames[0]
        self.rect = self.image.get_rect(center=center)

    def update(self):
        self.timer += 1
        if self.timer == 5:
            self.timer = 0
            self.index += 1
            if self.index == len(explosion_frames):
                self.kill()
            else:
                self.image = explosion_frames[self.index]


def play_music(path, loops=-1):
    pygame.mixer.music.load(path)
    pygame.mixer.music.play(loops)


def spawn_wave(image, count, speed):
    for i in range(count):
        x = random.randint(40, 600)
        enemies.add(Enemy(image, x, -40 - i * 120, speed))


player = Player()
lasers = pygame.sprite.Group()
enemies = pygame.sprite.Group()
explosions = pygame.sprite.Group()
last_shot = 0
score = 0
lives = 3
wave = 0
image, count, speed = WAVES[wave]
spawn_wave(image, count, speed)
pygame.mixer.music.set_volume(0.5)
play_music("assets/music/level.ogg")

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

    if lives > 0 and wave < len(WAVES):
        player.update()
        keys = pygame.key.get_pressed()
        now = pygame.time.get_ticks()
        if keys[pygame.K_SPACE] and now - last_shot >= 250:
            lasers.add(Laser(player.rect.centerx, player.rect.top))
            last_shot = now
            laser_sound.play()
        lasers.update()
        enemies.update()
        for enemy in enemies:
            if enemy.rect.top > 480:
                enemy.kill()
                lives -= 1
                hit_sound.play()
        hits = pygame.sprite.groupcollide(enemies, lasers, True, True, pygame.sprite.collide_mask)
        for enemy in hits:
            score += 10
            explosion_sound.play()
            explosions.add(Explosion(enemy.rect.center))
        crashes = pygame.sprite.spritecollide(player, enemies, True, pygame.sprite.collide_mask)
        for enemy in crashes:
            lives -= 1
            hit_sound.play()
            explosions.add(Explosion(enemy.rect.center))
        if not enemies:
            wave += 1
            if wave < len(WAVES):
                image, count, speed = WAVES[wave]
                spawn_wave(image, count, speed)
            else:
                play_music("assets/music/win.ogg", 0)
        if lives <= 0:
            play_music("assets/music/lose.ogg", 0)
    explosions.update()

    screen.fill((12, 14, 30))
    enemies.draw(screen)
    lasers.draw(screen)
    screen.blit(player.image, player.rect)
    explosions.draw(screen)
    score_text = font.render(f"Score: {score}", True, (240, 240, 240))
    screen.blit(score_text, (10, 10))
    lives_text = font.render(f"Lives: {max(lives, 0)}", True, (240, 240, 240))
    screen.blit(lives_text, lives_text.get_rect(topright=(630, 10)))
    if wave < len(WAVES):
        wave_text = font.render(f"Wave {wave + 1}", True, (240, 240, 240))
        screen.blit(wave_text, wave_text.get_rect(midtop=(320, 10)))
    if lives <= 0:
        message = font.render("Game over", True, (240, 240, 240))
        screen.blit(message, message.get_rect(center=(320, 240)))
    elif wave == len(WAVES):
        message = font.render("You win!", True, (240, 240, 240))
        screen.blit(message, message.get_rect(center=(320, 240)))
    pygame.display.flip()
    clock.tick(60)

pygame.quit()
quiz icon실력 점검

이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.

사운드와 게임의 손맛의 모든 레슨

직접 연습해 보세요: Pygame 플레이그라운드