https://www.youtube.com/watch?v=YPEkpwPrmPk&list=PLO-mt5Iu5TeZF8xMHqtT_DhAPKmjF6i3x&index=20&t=1749s
1. 유니티의 오디오
AudioClip : 오디오 및 사운드 파일 에셋 타입
Create Empty > AudioManager 생성
AudioSource : 에셋인 AudioClip을 재생시켜주는 컴포넌트
Play On Awake : 활성화 되어 있으면 최초 1회 자동 재생
AudioListener : 장면에서 재생 중인 오디오를 듣는 컴포넌트
Audio의 여러가지 필터가 존재한다.
2. 오디오 매니저
오디오를 관리할 스크립트 새로 생성 후 빈 오브젝트에 추가 (AudioManager.cs)
잊지 말고 즉시 Add Component
public class AudioManager : MonoBehaviour
{
public static AudioManager instance;
void Awake()
{
instance = this;
Init();
}
}
- 정적 메모리에 담기 위한 instance변수 선언
변수 선언
public class AudioManager : MonoBehaviour
{
public static AudioManager instance;
[Header("#BGM")]
public AudioClip bgmClip;
public float bgmVolume;
AudioSource bgmPlayer;
[Header("#SFX")]
public AudioClip[] sfxClips;
public float sfxVolume;
public int channels;
AudioSource[] sfxPlayers;
int channelIndex;
}
- 배경음과 관련된 클립, 볼륨, 오디오소스 변수 선언
- 코드 복사하여 효과음 코드로 편집
- 다량의 효과음을 낼 수 있도록 채널 개수 변수 선언
- sfx는 동시다발적으로 여러 사운드를 발생 시켜 채널시스템을 위해 배열 선언
- 몇번째 채널을 썻는지 저장하는 channelIndex
초기화 함수 Init()
void Init()
{
//배경음 플레이어 초기화
GameObject bgmObject = new GameObject("BgmPlayer");
bgmObject.transform.parent = transform;
bgmPlayer = bgmObject.AddComponent<AudioSource>();
bgmPlayer.playOnAwake = false;
bgmPlayer.loop = true;
bgmPlayer.volume = bgmVolume;
bgmPlayer.clip = bgmClip;
}
- 배경을 담당하는 자식 오브젝트를 생성
- bgmPlayer 초기화
- AddComponent 함수로 오디오소스를 생성하고 변수에 저장
- 설정 초기화
효과음 초기화
void Init()
{
...
//효과음 플레이어 초기화
GameObject sfxObject = new GameObject("SfxObject");
sfxObject.transform.parent = transform;
sfxPlayers = new AudioSource[channels];
for(int index = 0; index < sfxPlayers.Length; index++)
{
sfxPlayers[index] = sfxObject.AddComponent<AudioSource>();
sfxPlayers[index].playOnAwake = false;
sfxPlayers[index].volume = sfxVolume;
}
}
- 채널 값을 사용하여 오디오소스 배열 초기화
- 반복문으로 모든 효과음 오디오소스 생성하면서 저장
볼륨 bgm 0.5, sfx 0.2 설정
3. 효과음 시스템
모든 효과음 파일을 선택하고 효과음 배열변수에 드래그드랍
enum Sfx 생성
public enum Sfx { Dead, Hit, LevelUp = 3, Lose, Melee, Range = 7, Select, Win };
- 효과음과 1:1 대응하는 열거형 데이터 선언
- 열거형 데이터는 대응하는 숫자를 지정할 수 있어요
효과음 재생 함수 작성
public void PlaySfx(Sfx sfx)
{
sfxPlayers[0].clip = sfxClips[(int)sfx];
sfxPlayers[0].Play();
}
- 숫자로 쓰기 위해 명시적으로 (int) 선언
- 오디오소스의 클립을 변경하고 Play 함수 호출
쉬고 있는 플레이어에 실행시키게 수정
public void PlaySfx(Sfx sfx)
{
for(int index = 0; index < sfxPlayers.Length; index++)
{
int loopIndex = (index + channelIndex) % sfxPlayers.Length;
if (sfxPlayers[loopIndex].isPlaying)
continue;
channelIndex = loopIndex;
sfxPlayers[loopIndex].clip = sfxClips[(int)sfx];
sfxPlayers[loopIndex].Play();
break;
}
}
- 채널 개수만큼 순회하도록 채널인덱스 변수 활용
- coutinue : 반복문 도중 다음 루프로 건너뛰는 키워드
- 효과음 재생이 된 이후에는 꼭 break로 반복문 종료
효과음을 재생할 부분마다 재생함수 호출
public class GameManager : MonoBehaviour
{
...
public void GameStart(int id)
{
...
AudioManager.instance.PlaySfx(AudioManager.Sfx.Select);
}
IEnumerator GameOverRoutine()
{
...
AudioManager.instance.PlaySfx(AudioManager.Sfx.Lose);
}
IEnumerator GameVictoryRoutine()
{
...
AudioManager.instance.PlaySfx(AudioManager.Sfx.Win);
}
public class AchiveManager: MonoBehaviour{
...
IEnumerator NoticeRoutine()
{
uiNotice.SetActive(true);
AudioManager.instance.PlaySfx(AudioManager.Sfx.LevelUp);
yield return wait;
uiNotice.SetActive(false);
}
}
public class LevelUp : MonoBehaviour
{
...
public void show()
{
...
AudioManager.instance.PlaySfx(AudioManager.Sfx.LevelUp);
}
public void hide()
{
...
AudioManager.instance.PlaySfx(AudioManager.Sfx.Select);
}
}
public class Weapon : MonoBehaviour
{
...
void Fire()
{
...
AudioManager.instance.PlaySfx(AudioManager.Sfx.Range);
}
}
public class Enemy : MonoBehaviour
{
...
if (health > 0)
{
...
AudioManager.instance.PlaySfx(AudioManager.Sfx.Hit);
}
else
{
...
if(GameManager.instance.isLive)
AudioManager.instance.PlaySfx(AudioManager.Sfx.Dead);
}
}
}
- 언데드 사망 사운드는 게임 종료 시에는 나지 않도록 조건 추가
- if문 안쪽 로직이 한 줄이라면 중괄호 생략 가능
사운드가 2개 이상 있을 때 랜덤하게 재생하기
public class AudioManager : MonoBehaviour
public void PlaySfx(Sfx sfx)
{
...
int ranIndex = 0;
if (sfx == Sfx.Hit || sfx == Sfx.Melee)
{
ranIndex = Random.Range(0, 2);
}
channelIndex = loopIndex;
sfxPlayers[loopIndex].clip = sfxClips[(int)sfx + ranIndex];
...
}
}
4. 배경음 시스템
배경음을 재생하는 함수 작성
public void PlayBgm(bool isPlay)
{
if (isPlay)
{
bgmPlayer.Play();
}
else
{
bgmPlayer.Stop();
}
}
게임 시작 부분과 종료 부분에 해당 함수 호출
public class GameManager : MonoBehaviour
{
public void GameStart(int id)
{
...
AudioManager.instance.PlayBgm(true);
AudioManager.instance.PlaySfx(AudioManager.Sfx.Select);
}
IEnumerator GameOverRoutine()
{
...
AudioManager.instance.PlayBgm(false);
AudioManager.instance.PlaySfx(AudioManager.Sfx.Lose);
}
IEnumerator GameVictoryRoutine()
{
...
AudioManager.instance.PlayBgm(false);
AudioManager.instance.PlaySfx(AudioManager.Sfx.Win);
}
LevelUp 시에
Audio HighPass Filter를 담을 변수 선언(높은 음역대만 통과시키고, 낮음 음역대는 막음)
Audio HighPass Filter를 담을 변수 선언
public class AudioManager : MonoBehaviour
{
...
[Header("#BGM")]
...
AudioHighPassFilter bgmEffect;
...
void Init()
{
//배경음 플레이어 초기화
...
bgmEffect = Camera.main.GetComponent<AudioHighPassFilter>();
}
- 메인 카메라 접근은 Camera 클래스를 사용하면 간편해요'
필터를 켜고 끄는 함수도 작성
public void EffectBgm(bool isPlay)
{
bgmEffect.enabled = isPlay;
}
레벨 업 UI가 나타날 때 필터를 켜고 사라지면 끄도록 함수 호출
public class LevelUp : MonoBehaviour
{
public void show()
{
...
AudioManager.instance.EffectBgm(true);
}
public void hide()
{
...
AudioManager.instance.EffectBgm(false);
}
Audio HighPass Filter는 Listener Effect 계열
Sfx들을 Audio HighPass Filter의 효과를 받지 않게 보완
public class AudioManager : MonoBehaviour
{
void Init()
{
...
//효과음 플레이어 초기화
...
for(int index = 0; index < sfxPlayers.Length; index++)
{
...
sfxPlayers[index].bypassListenerEffects = true;
...
}
}
}
- 효과음 초기화 하는 부분에 byPassListenerEffects를 true로 변경
깃허브 올리기
Commit : ver 1.15
Description : Sound System
https://github.com/mekain80/CloneCode_Undead_Survivor
'게임개발 > 언데드서바이벌_골드메탈_클론코딩' 카테고리의 다른 글
[클론코딩_유니티_골드메탈] 뱀서라이크 따라만들기 14+ (캐릭터 해금🔓시스템) (0) | 2023.05.25 |
---|---|
[클론코딩_유니티_골드메탈] 뱀서라이크 따라만들기 14 (플레이 캐릭터🧑🤝🧑선택 ) (0) | 2023.05.11 |
[클론코딩_유니티_골드메탈] 뱀서라이크 따라만들기 13 (게임 시작과 종료) (0) | 2023.05.11 |
[클론코딩_유니티_골드메탈] 뱀서라이크 따라만들기 12 (레벨업🥳시스템) (0) | 2023.05.10 |
[클론코딩_유니티_골드메탈] 뱀서라이크 따라만들기 11+ (플레이어 무기 장착 표현하기) (0) | 2023.05.10 |