스푸79 기록 보관소

운석 피하기 게임 개발(15) - 배경음악, 효과음처리 본문

게임개발

운석 피하기 게임 개발(15) - 배경음악, 효과음처리

스푸79 2024. 10. 20. 17:00

 

취미로 게임을 개발하거나 인디게임개발자를 꿈꾸는 분들에게

사막의 오아시스와 같은 사이트가 있다. 그게 바로 opengameart.org라는 사이트이다.

https://opengameart.org

 

OpenGameArt.org

 

opengameart.org

 

2d와 3d asset부터 배경음악, 효과음까지 방대한 자료가 있는데, 무료로 받아서 사용할 수가 있다.

라이센스가 걸린 것도 대부분 게임 내에 CREDIT을 만들 때 THANKS TO 정도에 출처를 표기하면 된다.

 

이번 포스트에서는 사운드와 효과음을 넣을 생각이다.

우선 배경음악부터 처리해보자.

위의 사이트에서 art type을 music만 체크하고 space로 검색해보았다.

여러 배경음악 중 out there 라는 음악이 느낌상 지금 개발 중인 운석피하기와 가장 잘 어울릴 것 같아서 골랐다.

공유 주신 opengameart의 yd님께 진심으로 감사합니다.

 

 

 

인디게임 개발자라면 이런 음원을 사용할 때는 아래 LICENSE(S) 를 꼭 확인하기 바란다.

특히 스팀과 같은 게임 플랫폼에 개발한 게임을 무료로라도

상업적인 사이트에서 publish가 되는 경우,

라이센스 위반에 걸리는 경우가 종종 있다. 그러니 라이센스는 꼭 확인하길 바란다.

(사실, 라이센스 소송이 걸릴 정도로 본인이 개발한 게임이 대박 나는 걸 걱정하는 게 먼저긴 하다.)

 

게임에 사용할 사운드와 효과음을 opengameart 사이트에서 아래와 같이 정리해서 내려받았다.

-배경음악 bgm.ogg

-충돌효과음 collision.wav

-폭팔음 explosion.wav

-폭팔음(플레이어) player_explosion.wav

-보석획득시 효과음 player_jewerly.wav

-아이템획득시 효과음 player_upgrade.wav

 

음악과 효과음 처리하는 sound.py 코드는 아래와 같다.

import pygame
from enviroment import Enviroment as env

class Music():
    def __init__(self):
        self.ing = True
        pygame.mixer.music.load(env.GAME_SOUND_DIR + "bgm.ogg")
        
    def play(self):
        if self.ing:
            pygame.mixer.music.play(-1)
            
    def stop(self):
        pygame.mixer.music.stop()
        
    
class SoundEffect():
    def __init__(self):
        self.channel_list = []
        self.ing = True
        self.volume = 0.1
        self.collision_effect = pygame.mixer.Sound(env.GAME_SOUND_DIR + "collision.wav")
        self.enemy_explosion_effect = pygame.mixer.Sound(env.GAME_SOUND_DIR + "explosion.wav")
        self.player_bullet_effect = pygame.mixer.Sound(env.GAME_SOUND_DIR + "player_bullet.wav")
        self.player_explosion_effect = pygame.mixer.Sound(env.GAME_SOUND_DIR + "player_explosion.wav")
        self.player_jewerly_effect = pygame.mixer.Sound(env.GAME_SOUND_DIR + "player_jewerly.wav")
        self.player_upgrade_effect = pygame.mixer.Sound(env.GAME_SOUND_DIR + "player_upgrade.wav")

        for i in range(env.MAX_MIXER_CHANNEL):
            self.channel_list.append(pygame.mixer.Channel(i))
            
    def get_channel(self):
        for i in range(env.MAX_MIXER_CHANNEL):
            channel = self.channel_list[i]
            if not channel.get_busy():
                return channel
    
    def make_sound(self, effect):
        if self.ing:
            channel = self.get_channel()
            if channel != None:
                if effect == "player_bullet":
                    self.player_bullet_effect.set_volume(self.volume)
                    channel.play(self.player_bullet_effect)

                elif effect == "player_jewerly":
                    self.player_jewerly_effect.set_volume(self.volume)
                    channel.play(self.player_jewerly_effect)

                elif effect == "player_upgrade":
                    self.player_upgrade_effect.set_volume(self.volume)
                    channel.play(self.player_upgrade_effect)

                elif effect == "enemy_bullet":
                    self.enemy_bullet_effect.set_volume(self.volume)
                    channel.play(self.enemy_bullet_effect)

                elif effect == "enemy_explosion":
                    self.enemy_explosion_effect.set_volume(self.volume)
                    channel.play(self.enemy_explosion_effect)

                elif effect == "collision":
                    self.collision_effect.set_volume(self.volume)
                    channel.play(self.collision_effect)

                elif effect == "menu_bar":
                    self.menu_bar_effect.set_volume(self.volume)
                    channel.play(self.menu_bar_effect)

 

효과음 부분에서는 channel이라는 것을 사용했다.

channel을 사용하는 이유는 효과음이 중첩될 경우,

하나의 채널에서 동시에 소리가 나면 이상한 소리로 변질되는 증상이 발생한다.

그 증상을 해결하려면 다중 채널을 사용해야한다.

총 16개의 채널을 생성하고

효과음이 발생한 경우, busy한 상태인 경우는 skip하고 처리하는 소리가 없는 channel에 음원이 동작되도록 하는 것이다.

이런 처리를 위해서는 효과음은 1~2초 내로 짧은 음원을 쓰는 것이 좋다.

 

상황에 따른 효과음을 구분하기 위해 make_sound라는 메서드를 만들었다.

각 상황에 따라 make_sound를 적절하게 호출하여 상황에 맞는 효과음을 연출하도록 했다.

예를 들어 player_bullet은 사용자가 총알 발사할때 나는 소리이다.

아래 코드 처럼 player.py에서 fired 함수에 make_sound 함수를 호출하도록 코드를 추가한다.

def fired(self):    
    x3 = self.rect.centerx
    y3 = self.rect.centery
    missile = Missile(self.main, (x3, y3), self.dir, self.missile_sprites[self.dir])
    self.main.player_sprites.add(missile)

    self.main.sound_effect.make_sound("player_bullet")    

    ..(생략)..

 

item.py의 경우에는 ItemShield, ItemPower, ItemJewerly 등등 여러 player의 아이템 class가 있다.

아이템의 경우에 충돌 처리 시점에 소리를 넣으면 된다. 아래 코드는 보석과 플레이어가 충돌할때 발생하도록 처리했다.

class ItemJewerly(Item):
    def __init__(self, s_pos, d_pos, main):
        super().__init__(s_pos, d_pos, main)
        self.image = main.resources.item_jewerly
        self.rect = self.image.get_rect()
        self.rect.center = s_pos
        self.pos = s_pos
        
    def handle_collision(self, t_velocity, t_mass, damage):
        self.main.player.jewerly_up()
        self.main.sound_effect.make_sound("player_jewerly")
        self.kill()

 

SoundEffect 와 Music 클래스 모두 클래스 멤버변수로 self.ing 라는 건 두었다.

게임에서 사운드나 효과음을 끄고 하는 유저를 생각해서 두었다.

효과음을 켜고, 끄는 기능은 다음 포스트에서 메뉴 처리를 할때 적용할 예정이다.

15. sound.zip
3.92MB

 

음원이 들어가니 소스코드 용량이 확 늘었다.

GIF짤은 소리가 안 나서 영상으로 올려봤다.

영상 업로드는 4MB 밖에 안되서 짧은거로 밖에 안 올라가네요.

모두 개발되면 설치파일로 공유해 보도록 하겠습니다.

노잼이지만.^^;