전체 페이지뷰

2017년 10월 18일 수요일

Unity Tutorial: 2D Roguelike, part 11


Audio and Sound Manager



사운드와 음악을 추가해 보도록 하겠습니다. 단순한 2D게임이므로 Sound Manager 하나에서 전부 플레이 될 것입니다.

Hierarchy에 빈 오브젝트를 하나 생성하고 이름을 SoundManager로 정합니다. 여기에 백그라운드 뮤직과 사운드 효과의 두 가지 오디오 소스를 추가할 것입니다.

인스펙터에서 Add Component>Audio>Audio Source를 두 번 해서 오디오 소스 두 개를 추가합니다.



그 다음으로 이 SoundManager를 컨트롤할 스크립트를 생성할 것입니다. 프로젝트 창에서 Scripts 폴더를 선택하고 Create>C# Script하여 스크립트를 하나 만들고 그 이름을 SoundManager로 정한 후 에디터로 열어봅시다.

역시 변수들을 먼저 선언합니다.

public AudioSource efxSource; //효과음 레퍼런스
public AudioSource musicSource; // 배경음악 레퍼런스
public static SoundManager instance = null;  // 싱글톤 패턴
public float lowPitchRange = 0.95f; //  사운드 ㅋ크기를 위 아래 5%씩
public float highPitchRange = 1.05f; // 변화를 줌
cs

그리고 Awake()에서 싱글턴 패턴을 구현합니다.
void Awake()
{
    if (instance == null)
        instance = this;
    else
        Destroy(gameObject);
    DontDestroyOnLoad(gameObject);
}
cs
싱글턴 패턴이므로 다른 클래스에서 SoundManager의 메소드를 직접 호출하여 사용하게될 것입니다.

효과음이 한 개인 경우와 여러개인 경우로 나눠서 메소드를 작성합니다.

효과음이 한개일 경우 PlaySingle()이라는 메소드로 해결합니다.
public void PlaySingle(AudioClip clip)
{
    efxSource.clip = clip;
    efxSource.Play();
}
cs

효과음이 여러개라면, 그 중 어떤 것을 어떤 피치로 플레이할 것인가를 정해줄 RandomizeSfx()를 작성합니다.
public void RandomizeSfx(params AudioClip[] clips)
{
    // 받아온 여러개의 클립중 하나 선택
    int randomIndex = Random.Range(0, clips.Length);
    // 피치를 결정
    float randomPitch = Random.Range(lowPitchRange, highPitchRange);
    efxSource.pitch = randomPitch;
    efxSource.clip = clips[randomIndex];
    efxSource.Play();
}    
cs

이제 저장하고 유니티로 돌아갑시다. 작성된 스크립트를 드래그하여 SoundManager 오브젝트에 연결합니다. 그리고 인스펙터의 첫 오디오 소스를  스크립트의 Efx Source 프로퍼티에, 두번째 오디오 소스를 Music Source 프로퍼티에 드래그해서 연결합니다.


다 연결했으면 인스펙터에서 두번째 Audio Source를 선택하고,배경음악용으로 AudioClip에 scavengers_music을 연결, Loop에 체크합니다.


첫번째 Audio Source는 효과음 용이므로 일단 Play On Awake에만 체크 해제하고, 플레이를 눌러 테스트 해봅시다. 음악이 잘 들린다면 다음 단계로 넘어갑니다.

효과음들은 플레이어의 행위에 맞게 나올 수 있도록 Player 스크립트에서 작성할 것입니다. Player 스크립트를 다시 엽시다.

7개의 AudioClip 변수들을 추가합니다.

public AudioClip moveSound1;
public AudioClip moveSound2;
public AudioClip eatSound1;
public AudioClip eatSound2;
public AudioClip drinkSound1;
public AudioClip drinkSound2;
public AudioClip gameOverSound;
cs

움직이는 소리, 음식을 먹는 소리, 음료를 마시는 소리, 게임오버 소리의 네 종류로 이루어져 있습니다.

이 중 움직이는 소리는 AttemptMove에 들어갑니다.
protected override void AttemptMove<T>(int xDir, int yDir)
{        
    ...
    RaycastHit2D hit;
    if (Move(xDir,yDir,out hit))
    {
        SoundManager.instance.RandomizeSfx(moveSound1, moveSound2);
    }
    ...
}
cs
Move로 판정한 결과 움직일 수 있다면 SoundManager가 두 개의 사운드 중 임의로 골라 플레이하도록 합니다.

먹고 마시는 소리는 OnTriggerEnter2D에 들어갑니다.
private void OnTriggerEnter2D(Collider2D other)
{
    ...
    else if (other.tag == "Food")
    {
        food += pointsPerFood;
        foodText.text = "+" + pointsPerFood + " Food:" + food;
        SoundManager.instance.RandomizeSfx(eatSound1, eatSound2);
        other.gameObject.SetActive(false);
    }
    // Soda도 포인트 추가, 사라지게 함
    else if (other.tag == "Soda")
    {
        food += pointsPerSoda;
        foodText.text = "+" + pointsPerSoda + " Food:" + food;
        SoundManager.instance.RandomizeSfx(drinkSound1, drinkSound2);
        other.gameObject.SetActive(false);
    }
}
cs


마지막으로 CheckIfGameOver에 게임오버 사운드가 들어갑니다.
private void CheckIfGameOver()
{
    // 푸드 포인트가 0 이하면 GameOver호출
    if (food <= 0)
    {
        SoundManager.instance.PlaySingle(gameOverSound);
        SoundManager.instance.musicSource.Stop();
        GameManager.instance.GameOver();
    }           
}
cs

여기서 스크립트를 저장하고 유니티로 돌아갑니다.

Hierarchy의 Player를 선택해보면 새로 설정한 7개의 오디오클립 프로퍼티가 추가되어 있습니다. 여기에 각각의 클립을 연결합니다.



Enemy도 역시 내야할 소리가 있습니다. Enemy 스크립트를 열고 변수를 추가합니다.

public AudioClip enemyAttack1;
public AudioClip enemyAttack2;
cs

그리고 OnCantMove 메소드의 아래 부분에서 오디오 플레이 메소드를 사용합니다.
protected override void OnCantMove<T>(T component)
{
    ...
    SoundManager.instance.RandomizeSfx(enemyAttack1, enemyAttack2);
}
cs

저장 후 다시 유니티로 돌아가서 프로젝트창의 Prefabs폴더 안의 Enemy1, Enemy2 프리팹을 Shift+클릭하여 동시 선택하면 Enemy Attack 1,2 프로퍼티가 나타납니다. 여기에 역시 그림과 같이 오디오클립을 연결합니다.



벽이 부서지는 사운드도 추가해야 합니다.
Scripts폴더로 가서 Wall 스크립트를 에디터로 열고 두개의 변수를 추가합니다.

public AudioClip chopSound1;
public AudioClip chopSound2;
cs

소리는 DamageWall()에서 담당합니다.
public void DamageWall(int loss)
{
    SoundManager.instance.RandomizeSfx(chopSound1, chopSound2);
    ...
}
cs

스크립트를 저장하고 유니티로 돌아가서 Prefabs폴더의 Wall 여덟 개 전체를 선택하고 Chop Sound 프로퍼티를 연결합니다.



테스트해 보면 모두 잘 작동됩니다.

댓글 없음:

댓글 쓰기