본문 바로가기
유니티3D

유니티3D - BGM(배경음악) 바꾸기 #3. 스크립트 설명편(2)

지난 시간에 이어 스크립트 설명을 재개하도록 하겠습니다.

https://itadventure.tistory.com/417

 

유니티3D - BGM(배경음악) 바꾸기 #2. 스크립트 설명편(1)

지난 시간에는 마을 박스에 진입할 때 배경음악을 바꾸는 부분을 살펴보았지요. 스크립트를 여기 저기 채워넣고 설정만을 바꿔보았지 작동원리에 대한 설명은 없었는데요. 오늘은 그 부분을 살

itadventure.tistory.com

플레이어가 트리거에 충돌할때 카메라에 들어 있는 Play Music Operator 스크립트 컴포넌트에
배경음악을 재생해달라고 요청하는 부분이 실행되는데요.

Play Music Operator 컴포넌트에는 배경음악명에 해당하는 실제 배경음악 오디오 음원들이 들어있습니다.
한글로 명칭하자면 배경음악 재생기 컴포넌트가 되겠습니다 :)

여기서 BGM List 이 배경음악 속성인데요.
여지껏 보아 오신 것과 다른 정의 방법으로 배열이란 걸로 구성되어 있습니다.
배열이란 하나의 속성에 여러개의 값을 입력할 수 있는 것을 의미합니다.
그렇기에 여러개의 배경음악을 입력할 수 있는 것이지요.

이 부분을 정의한 스크립트는 아래와 같습니다

 

[System.Serializable]
public struct BgmType
{
    public string name;
    public AudioClip audio; 
}
public BgmType[] BGMList;

순차적인 이해를 위해 public struct BgmType { ... } 부터 설명드리겠습니다.
struct구조라는 뜻의 영어 단어인데요.
C++ 또는 C# 언어에서는 여러 속성을 하나로 묶어서 사용할때 이 기능을 사용합니다.

배경음악 1개에 대해 다음과 같은 속성이 있다고 칩시다.

- 배경음악이름
- 배경음악파일

 

이 때 이 2개의 다른 종류의 속성을 하나로 묶어서 관리하고 싶을 때 사용하는 것이 바로 구조체입니다.
위를 구조체로 정의하는 방법은 아래와 같습니다.

 

[System.Serializable]
public struct BgmType
{
    public string name;
    public AudioClip audio; 
}

그리고 이 구조체를 이용해서 아래와 같이 속성을 정의하면 

public BgmType 변수;

인스펙터 창에서는 아래와 같이 노출됩니다.

스크립트에서는 이 속성에 대해 아래와 같이 접근이 가능합니다.

변수.Name
변수.Audio

참고로 유니티에서 이렇게 인스펙터 창에 구조체를 노출하려면
구조체 선언 앞에 [System.Serializable] 선언이 필수입니다.
씨리얼라이즈라고 해서 이 한줄이 없으면 BgmList 자체도 아예 나오지 않습니다.

자 이제 여기서 다음 단계로 배열을 살펴봅시다.
배열이란 하나의 속성에 동일한 유형의 값을 여러개 정의하는 것인데요.

배열에 대한 이해를 돕기 위해 단순 배열을 잠깐 살펴보도록 하겠습니다.
만일 아래와 같이 속성을 정의한다면,

public AudioClip [] 배경음원; 

배경음원이라는 배열은 인스펙터 창에 아래와 같이 보여질 겁니다.
Size 는 임의로 2를 입력하였지요.

배경음악이 3개 필요하면 Size 에 3을 입력하고,
배경음악이 5개 필요하면 Size 에 5를 입력하면 됩니다.
그러면 그 갯수만큼 배경음원을 첨부할 수 있습니다.

그리고 각각의 배경음원은 스크립트에서 아래와 같이 접근이 가능한데요.
[] 안에 있는 숫자를 배열첨자라고 합니다.
배열첨자가 첫번째 배경음악이 [1]이 아닌 [0]인 점에 주의합시다. 그렇기에 5번째 배경음악은 배열첨자가 [4]가 됩니다.

배경음원[0]
배경음원[1]
배경음원[2]
배경음원[3]
배경음원[4]

이것은 단순 배열입니다. 사실 배경음악 목록을 이렇게 관리해도 됩니다.
스크립트 구성은 이 방법이 더 단순합니다.
이 경우 0번은 무슨 배경음악이고 1번은 무슨 배경음악인지
번호를 어딘가 정리해놓은 다음 사용해야 합니다.

하지만 배경음악을 이름으로 관리하기 위해 여기서는 구조체 배열을 사용했는데요.
말그대로 구조체를 배열로 정의한 것입니다.

public BgmType2[] BGMList2;

만일 아래와 같이 속성을 정의한 경우

스크립트에서는 각각의 배경음악 이름과 배경음악 음원에 대해 아래와 같이 접근이 가능합니다.

BGMList[0].name
BGMList[0].audio
BGMList[1].name
BGMList[1].audio

배경음악의 목록에 대한 구조체 배열구조도 대강 알았으니까
실제 배경음악을 재생하는 부분을 알아보겠습니다.

먼저, 배경음악 재생기 컴포넌트도 처음에 한번만 실행하는 부분이 일부 필요한데요.
지난번에도 보았던 Start() 메소드입니다.
이 메소드는 씬에 배치될 때 한번만 실행된다고 말씀드린 바가 있지요?
여기서는 어떤 일을 하는지 살펴봅시다.

void Start()
{
    BGM = gameObject.AddComponent<AudioSource>();
    BGM.loop = true;
    if (BGMList.Length > 0) PlayBGM(BGMList[0].name);
}

gameObject.AddComponent 는 컴포넌트를 새로 생성하는 명령인데요.
시용법은 아래와 같습니다  gameObject.AddComponent<컴포넌트이름>();

여기서는 유니티 내장 컴포넌트인 AudioSource(오디오소스) 라는 컴포넌트를 생성합니다.
오디오 소스는 소리를 재생하는 소리발생기 컴포넌트입니다.
표준 C#에서 사용하는 아래와 같은 유형의 방법은 일반 컴포넌트 정의로는 유니티에서 사용할 수 없으니 주의해 주세요.

BGM = new AudioSource();  // 사용 불가

그리고 생성만 해놓으면 얼마 후 사라지기 때문에 컴포넌트 참조를 BGM이란 속성에 넣어줍니다.
BGM 속성은 아래와 같이 정의되어 있습니다.
private 라서 인스펙터 창에서는 보이지 않습니다.

private AudioSource BGM;

그리고 반복 재생하도록 설정을 변경합니다.

BGM.loop = true;

이 것은 인스펙터 창에 오디오 컴포넌트가 있다고 가정할 때 loop 체크상자를 체크한 것과 동일한 효력을 갖습니다.

그리고 나서 배경음악이 1개라도 있으면, PlayBGM(BGMList[0].name); 명령을 실행합니다.

if (BGMList.Length > 0) PlayBGM(BGMList[0].name);

배경음악 배열의 갯수는 BGMList.Length 입니다.
배경음악이 전혀 없는 경우 이 값은 0이지만,
우리가 인스펙터창에서 2를 입력해놓았다면 이 값은 Start()가 실행될 때 2값이 됩니다.


아래 스크립트는 조건문이라고 하는데요. if 만일, 괄호안의 조건이 맞다면 ( BGMList.Length > 0 이라면 ) 

if (BGMList.Length > 0)

그 뒷 부분을 실행해라~ 그런 의미입니다.
뒷 부분은 아래와 같이 구성되어 있습니다.

PlayBGM(BGMList[0].name);

BGMList[0].name 은 첫번째 배열의 name 속성입니다.
아래와 같이 입력해놓았다면 'happy'가 됩니다.

결국 첫번째 배경음악 'happy'를 재생해달라고 PlayBGM() 메소드에게 요청하는 것이지요.

PlayBGM 메소드는 아래와 같이 구성되어 있습니다.
이 메소드는 플레이어가 마을 입장 트리거에 충돌할 때도 공용으로 사용하는 메소드입니다.
이제 드디어 트리거 충돌시 실행되는 부분을 살펴보게 되는 것이지요.

public void PlayBGM(string name)
{
    if (NowBGMname.Equals(name)) return;

    for (int i = 0; i < BGMList.Length; ++i)
        if (BGMList[i].name.Equals(name))
        {
            BGM.clip = BGMList[i].audio;
            BGM.Play();
            NowBGMname = name;
        }
}

또 조건문이 나왔습니다. 조건문은 컴퓨터 언어에서 가장 많이 사용됩니다.
아래 명령은 현재 재생중인 배경음악과 동일한 음악을 재생요청받을 경우 아무 일도 하지 않고 끝냅니다.
마을 입구에서 왔다 갔다 할때 똑같은 배경음악이 처음부터 리셋되어 다시 재생되는 것을 막기 위해 필요한 부분입니다.

if (NowBGMname.Equals(name)) return;

여기서 NowBGMname 은 현재 재생중인 음악을 보관할 용도의 속성입니다.
배경음악이 바뀔 때마다 아래와 같이 속성값을 바꿔주어
현재 재생중인 배경음악이 무엇인지 알 수 있도록 관리하는 속성입니다.

NowBGMname = name;

다음으로는 배경음악 배열의 모든 요소를 하나 하나 탐색합니다.
배경음악이 1,000개라면 1000개를 모두 탐색하는데요.
컴퓨터는 꽤나 속도가 빨라서 1,000개를 탐색하는 것은 눈깜짝할 사이에 지나갑니다.

아래는 배경음악의 갯수만큼 반복하는 명령인데요.

for (int i = 0; i < BGMList.Length; ++i)

for ( ... ) 문은 반복문이라고 하여 이 뒷 부분을 여러번 반복해 실행합니다.
BGMList.length 값이 2라면 0, 1 이렇게 2번 반복해 실행합니다.
그 과정에 첫번째 반복과정에는 i 라는 정수형 변수에 0값이 입력되고,
두 번째 반복과정에는 i 라는 정수형 변수에 1값이 입력됩니다

반복문이 실행되면서 그 안에서 조건문이 작동하는데요.
배열의 [i]  순번의 요소의 .name 속성이 요청받은 배경음악 name과 같은지 비교합니다.

if (BGMList[i].name.Equals(name))

같은게 있다면 if(...) 뒷 부분이 실행되지만,
없다면 실행하지 않습니다.

그리고 그 다음 부분은 메소드처럼 중괄호 { } 로 둘러싸여 있는데요.
C#에서는 여러개의 명령을 실행하고자 할 경우 이와 같이 중괄호로 묶어 주어야 합니다.

{
    BGM.clip = BGMList[i].audio;
    BGM.Play();
    NowBGMname = name;
}

이 중괄호가 실행되는 조건은 일치하는 배경음악 제목을 찾았을 때입니다.
그렇기 때문에 BGMList[i].name 에는 요청받은 배경음악 이름이,
BGMList[i].audio 에는 요청받은 배경음악의 음원이 들어있습니다.

그래서 BGM.clip 속성에 이 배경음악을 앞으로 재생하라고 준비시킨 다음에,

BGM.clip = BGMList[i].audio;

배경음악 재생을 새로 시작합니다.

BGM.Play();

그리고 현재 재생이 되는 배경음악의 제목을 NowBGMname 속성에 넣는 것이지요.

NowBGMname = name;

그림으로 보면 아래와 같습니다.
처음에는 이러한 메시지 전달 방식이 혼동될수 있으나 익숙해지면 편해집니다.

이로서 배경음악 재생스크립트 설명이 완료되었습니다.
궁금하신 점은 문의 주세요 :)

오늘도 여기까지 읽어주셔서 감사합니다.


오늘도 성경말씀 한 구절 전해드립니다 :)

예루살렘을 위하여 평안을 구하라 예루살렘을 사랑하는 자는 형통하리로다
- 시편 122:6 -


다음 게시글 : NPC 대화창 #1

https://itadventure.tistory.com/419

 

유니티3D - NPC 대화창 #1

지난번까지는 마을입장에 따른 배경음악에 대한 스크립트를 3회에 걸쳐 다루어 보았는데요. https://itadventure.tistory.com/418 유니티3D - BGM(배경음악) 바꾸기 #3. 스크립트 설명편(2) 지난 시간에 이어

itadventure.tistory.com