게임 내에서 환경소리를 이용하면 더욱 생동감 있는 게임을 구성할 수 있습니다. 기능 및 구현과정 자체는 매우 단순하지만 편리하게 씬 내에 환경 사운드를 배치할 수 있기에 이를 정리하였습니다.
💬 목차
- 이 클래스의 기능은 비어있는 게임 오브젝트에 AmbientArea 컴포넌트를 추가하여 버튼을 누르면 자동으로 사운드를 재생할 준비를 마치게되며, 편리하게 3D사운드의 영역을 조절할 수 있도록 해줍니다.
- 플레이어가 오디오 소스의 maxDistance보다 멀리 떨어지게되면 자동으로 해당 오디오는 멈추며, 영역내로 들어오면 다시 오디오소스가 재생되게 합니다.
- 이 기능은 [편리하게 소리를 담당하는 사운드 매니저 구현]의 기능 일부를 포함합니다.
✅ 구현
· AmbientArea.cs
- 런타임 도중 실제로 기능을 작동하는 클래스입니다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif
[RequireComponent(typeof(AudioSource))]
[RequireComponent(typeof(SphereCollider))]
public class AmbientArea : MonoBehaviour
{
private readonly static string _TRIGGER_TAG = "Player";
[field: Header("오디오 타입(EFFECT / BGM)")]
[field: SerializeField] public SoundType SoundType { private set; get; }
private AudioSource mAudioSource; // 오디오 소스
private void Awake()
{
mAudioSource = GetComponent<AudioSource>();
}
private void OnTriggerEnter(Collider other)
{
if (other.tag == _TRIGGER_TAG)
{
mAudioSource.Play();
}
}
private void OnTriggerExit(Collider other)
{
if (other.tag == _TRIGGER_TAG)
{
mAudioSource.Stop();
}
}
}
#if UNITY_EDITOR
[CustomEditor(typeof(AmbientArea))]
public class AmbientAreaEditor : Editor
{
public override void OnInspectorGUI()
{
DrawDefaultInspector();
GUILayout.Label("\n\nAmbient Area 기본 설정");
if(GUILayout.Button("기본 설정"))
{
AmbientArea ambientArea = (AmbientArea)target;
ambientArea.gameObject.layer = LayerMask.NameToLayer("Ignore Raycast");
ambientArea.GetComponent<SphereCollider>().isTrigger = true;
AudioSource audioSource = ambientArea.GetComponent<AudioSource>();
audioSource.spatialBlend = 1.0f;
audioSource.rolloffMode = AudioRolloffMode.Linear;
audioSource.minDistance = 0f;
audioSource.playOnAwake = false;
audioSource.loop = true;
audioSource.outputAudioMixerGroup = SoundManager.Instance.AudioMixer.FindMatchingGroups(ambientArea.SoundType.ToString())[0];
ambientArea.gameObject.name = $"AMBIENTAREA_{audioSource.clip.name}";
}
GUILayout.Label("\n\n오디오 소스의 maxDistance를 localScale로 설정");
if(GUILayout.Button("maxDistance를 > localScale로"))
{
AmbientArea ambientArea = (AmbientArea)target;
ambientArea.transform.localScale = Vector3.one * ambientArea.GetComponent<AudioSource>().maxDistance * 2.0f;
}
GUILayout.Label("\n\nlocalScale를 오디오소스의 maxDistance로 설정");
if(GUILayout.Button("localScale > maxDistance를"))
{
AmbientArea ambientArea = (AmbientArea)target;
ambientArea.GetComponent<AudioSource>().maxDistance = (ambientArea.transform.localScale * 0.5f).x;
}
}
}
#endif
[RequireComponent(typeof(AudioSource))]
[RequireComponent(typeof(SphereCollider))]
- 이 클래스는 오디오소스와 SphereCollider포함합니다.
- 오디오소스 3D 영역은 원형태로 범위가 설정되어있기때문에 SphereCollider가 가장 적합하다고 판단하여 사용하였습니다.
private readonly static string _TRIGGER_TAG = "Player";
- 오디오 리스너 컴포넌트를 포함하는 대상의 태그 트리거영역에서 감지할 수 있도록 정합니다.
- 일반적으로 플레이어(또는 카메라)가 오디오 리스너를 지니기에 본 글에서는 Player로 설정하였습니다.
[field: Header("오디오 타입(EFFECT / BGM)")]
[field: SerializeField] public SoundType SoundType { private set; get; }
- 해당 사운드의 타입을 설정합니다.
- 이전에 구현한 사운드매니저의 불륨 설정을 하기 위해 사용합니다.
- BGM, EFFECT등 타입별로 Ambient 소리를 설정할 수 있습니다.
private void OnTriggerEnter(Collider other)
{
if (other.tag == _TRIGGER_TAG)
{
mAudioSource.Play();
}
}
private void OnTriggerExit(Collider other)
{
if (other.tag == _TRIGGER_TAG)
{
mAudioSource.Stop();
}
}
- _TRIGGER_TAG가 같은 대상이 영역에 접근하거나, 영역에서 빠져나가면 소리를 재생하고, 멈춥니다.
· Editor.cs
- 런타임도중이 아닌 에디터에서 개발자에게 편리한 기능을 지원하기위해 사용하는 에디터 클래스입니다.
#if UNITY_EDITOR
[CustomEditor(typeof(AmbientArea))]
public class AmbientAreaEditor : Editor
{
public override void OnInspectorGUI()
{
DrawDefaultInspector();
GUILayout.Label("\n\nAmbient Area 기본 설정");
if(GUILayout.Button("기본 설정"))
{
AmbientArea ambientArea = (AmbientArea)target;
ambientArea.gameObject.layer = LayerMask.NameToLayer("Ignore Raycast");
ambientArea.GetComponent<SphereCollider>().isTrigger = true;
AudioSource audioSource = ambientArea.GetComponent<AudioSource>();
audioSource.spatialBlend = 1.0f;
audioSource.rolloffMode = AudioRolloffMode.Linear;
audioSource.minDistance = 0f;
audioSource.playOnAwake = false;
audioSource.loop = true;
audioSource.outputAudioMixerGroup = SoundManager.Instance.AudioMixer.FindMatchingGroups(ambientArea.SoundType.ToString())[0];
ambientArea.gameObject.name = $"AMBIENTAREA_{audioSource.clip.name}";
}
GUILayout.Label("\n\n오디오 소스의 maxDistance를 localScale로 설정");
if(GUILayout.Button("maxDistance를 > localScale로"))
{
AmbientArea ambientArea = (AmbientArea)target;
ambientArea.transform.localScale = Vector3.one * ambientArea.GetComponent<AudioSource>().maxDistance * 2.0f;
}
GUILayout.Label("\n\nlocalScale를 오디오소스의 maxDistance로 설정");
if(GUILayout.Button("localScale > maxDistance를"))
{
AmbientArea ambientArea = (AmbientArea)target;
ambientArea.GetComponent<AudioSource>().maxDistance = (ambientArea.transform.localScale * 0.5f).x;
}
}
}
#endif
if(GUILayout.Button("기본 설정"))
- 버튼을 표시하여 해당 버튼을 누르면 기본적인 설정을 하도록 합니다.
- 기본적인 설정에는 레이어 설정, 콜라이더 설정, 오디오소스 설정, 오브젝트 이름설정을 합니다.
if(GUILayout.Button("maxDistance를 > localScale로"))
- 오디오소스의 maxDistance를 SphereCollider의 영역과 일치하도록 설정합니다.
if(GUILayout.Button("localScale > maxDistance를"))
- 위 기능과 반대로 SphereCollider의 영역의 크기를 기준으로 maxDistance를 설정합니다.
✅ 사용 방법
1. GameObject을 생성합니다.
- 빈 오브젝트인 Empty GameObject를 추천합니다.
2. 생성한 오브젝트에 AmbientArea 컴포넌트를 추가합니다.
- 자동으로 AudioSource와 SphereCollider 컴포넌트가 함께 추가됩니다.
3. AudioSource 컴포넌트의 AudioClip에 원하는 사운드를 설정합니다.
- 본 글에서는 대장간에서 망치를 두드리는 소리인 "HAMMER_HIT_1"을 설정하였습니다.
4. AmbientArea 컴포넌트에서 "기본 설정" 버튼을 눌러 설정을 자동으로 해줍니다.
- 오브젝트의 이름이 변경되고, 레이어가 설정되고 여러가지 옵션이 변경된것을 볼 수 있습니다.
5. 오디오 소스의 영역 크기를 설정합니다.
- 오브젝트의 스케일 또는 오디오 maxDistance의 크기를 설정하고 크기를 자동으로 맞추는 버튼을 사용하여 크기를 동일하게 맞춥니다.
✅ 결과
- 영역에 접근하면 사운드가 들리고, 벗어나면 사운드가 꺼집니다.
- 기능 자체는 매우 단순하지만, 이것을 구축하기위한 설정이 매우 편리하다는 장점이 있습니다.
🖋️ 마치며
Unity의 AudioSource 3D는 소리가 발생하는 위치와 청취자 사이의 거리에 따라 볼륨과 효과를 계산하는 3D 사운드 시스템입니다. 만약 오디오 리스너가 AudioSource의 최대 거리보다 멀어진다면, 오디오 출력이 자연스럽게 감소됩니다. 이것은 3D 사운드 시스템의 일부로써 오디오가 멀어지면 볼륨이 줄어들기 때문입니다.
따라서, 일시 정지를 사용하는 것은 최대 거리보다 멀리 떨어진 AudioSource에서 사운드를 제어하는 데 도움이 될 수 있습니다. 그러나 이것이 "좋다"는 것은 상황에 따라 다르기 때문에, 어떤 상황에서 사용해야 하는지 정확히 알아야 합니다.
예를 들어, 오디오 리스너와 AudioSource 사이의 거리가 일시적으로 멀어질 때 일시정지를 사용하면 사용자에게 혼란스러울 수 있습니다. 또한, 멀어진 AudioSource에서 일시정지된 사운드를 다시 시작하려면 일부 조건이 충족되어야 하며, 이것은 프로그래밍의 복잡성을 증가시킬 수 있습니다.
따라서, 최대 거리보다 멀어진 AudioSource에서 일시정지를 사용하는 것은 상황에 따라 다르며, 게임 또는 응용 프로그램의 요구 사항에 따라 다릅니다. 일반적으로, 멀어진 AudioSource에서 일시정지를 사용할 때는 사용자 경험을 고려하여 조심스럽게 사용하는 것이 좋습니다.
음원이 특정 거리를 넘어 이동할 때 AudioSource를 일시 중지하면 장면에서 활성 오디오 소스의 수를 줄이고 처리 리소스를 확보할 수 있으므로 최적화 동작이 될 수 있습니다.
장면에 많은 수의 AudioSource 구성 요소가 있고 그 중 많은 구성 요소가 너무 멀리 떨어져 있기 때문에 청취자에게 들리지 않는 사운드를 재생하는 경우 일시 중지하면 성능이 향상될 수 있습니다.
그러나 사용자 경험의 품질과 최적화의 균형을 맞추는 것이 중요합니다. 사운드가 게임이나 응용 프로그램의 중요한 부분이고 사운드 부재가 눈에 띄거나 거슬리는 경우 청취자가 멀리 떨어져 있어도 계속 재생하고 싶을 수 있습니다. 궁극적으로 거리에 따라 AudioSource를 일시 중지할지 여부는 프로젝트의 특정 요구 사항과 제약 조건에 따라 결정됩니다.
'unity game modules' 카테고리의 다른 글
[유니티] 스탯 시스템(1) - 디자인 (0) | 2023.03.24 |
---|---|
[유니티] 레벨, 경험치 시스템 (0) | 2023.03.24 |
[유니티] 자동 스크롤 (0) | 2023.03.22 |
[유니티] 외곽선 쉐이더 구현 및 관리 (0) | 2023.03.21 |
[유니티] Skybox Blender (0) | 2023.03.09 |