統一音声管理


統一音声管理


この文章では、unityサウンドをコードでロードして再生する方法について説明します.
まず、Unityの音は少し大きいです.
  • mp3 Player == Audio Source
  • mp 3音源=Audio Clip
  • 視聴者(耳)=Audio Listener
  • 三つに分類する.
    開始する前に、サウンドマネージャというc#スクリプトファイルを作成して、すべてのサウンドを管理します.
  • 音をテストするテスト音声スクリプトも作成した.
  • (衝突時に音がするかどうかをテストするために使用)
    また、サウンドのタイプを管理するためにDefineスクリプトも事前に作成されます.
    Defineスクリプトは、事前定義が必要な音や他の音を収集するために使用されます.(Bgm、Effectなど、音声用のタイプ)
    まずTestSoundでコードを作成して、音がどのように出ているかを理解します.
    まずstart()、update()関数は作成しません
    まず,衝突が発生したときに衝動物体からAudioソースを抽出するコードをテストする.
    public AudioClip audioClip1;
    
    private void OnTriggerEnter(Collider other)
    {
    	AudioSource audio = GetComponent<AudioSource>();
        audio.PlayOneShot(audioclip1);
    }
    まずaudipClip 1を公表します.
    デフォルトでは、default値はprivateなので、ドラッグ&ドロップ機能などの汎用エンジンで使用するには開く必要があります.
    次に、汎用エンジンでオブジェクト(立方体でも何でも)を作成し、TestSoundを構成部品として貼り付けます.
    OnTriggerEnterは自動的に完了します.

    汎用エンジンに戻り、右側にTestSound 2を付け、以下は公開オープンのaudioClip 1です.
    ここで自分が実行したいaudioClipをドラッグ&ドロップして実行し、私たちのキャラクターがcubeを通過するたびにオーディオクリップを再生します.
    現在、キャラクターは直接キューブを通過しています.キャラクターと物体の衝突を実現するには、プレイヤーと物体の間にRigid Body接続が必要ですが、isTriggerを閉じます.
    音と物体の衝突を理解しました
    Sound Managerが音声を管理する方法について詳しく説明します.
    サウンドマネージャを使用してサウンドを管理する理由は
    これからはゲームが大きくなります(大きくならなくても)
    音を1つのオブジェクトにドラッグすることで音を管理できないため、音が大きいと音の種類が非常に多くなります.
    まず最後のコードから見てみましょう
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class SoundManager
    {
        AudioSource[] _audioSources = new AudioSource[(int)Define.Sound.MaxCount]; // 용도를 나누어서 만들어 놓자.
        // mp3 audiosource를 담을 배열 선언
    
        // 캐싱 역할을 할 _audioClips 딕션어리 
        // 캐싱은 사운드를 재생할때마다 계속 path를 입력받아 사운드를 찾는 방식이 아닌 한번 사용한 사운드는 딕셔너리로 관리하여 보다 빠르게 처리하기 위해서 캐싱용 딕션너리를 사용하는 것이다.
        Dictionary<string, AudioClip> _audioClips = new Dictionary<string, AudioClip>();
    
        public void init()
        {
            GameObject root = GameObject.Find("@Sound");
            if(root == null)
            {
                root = new GameObject { name = "@Sound" };
                Object.DontDestroyOnLoad(root);
    
                string[] soundNames = System.Enum.GetNames(typeof(Define.Sound));
    
                for(int i = 0; i < soundNames.Length - 1; i++)
                {
                    GameObject go = new GameObject { name = soundNames[i] };
                    _audioSources[i] = go.AddComponent<AudioSource>(); // 위에서 만든 _audioSources에 넣어준다.
                    go.transform.parent = root.transform;
                }
                // soundName을 돌면서 새로운 GameObject를 만들어준다.
    
                _audioSources[(int)Define.Sound.Bgm].loop = true; // Bgm같은 경우에는 루프로 계속 사운드가 나도록 해준다.
            }
    
        }
        
        public void Clear()
        {
            foreach(AudioSource audioSource in _audioSources)
            {
                audioSource.clip = null;
                audioSource.Stop();
            }
            _audioClips.Clear();
        }
    
        public void Play(string path, Define.Sound type = Define.Sound.Effect, float pitch = 1.0f) // path로 경로를 받아주고 pitch = 소리 속도 조절
        {
            AudioClip audioclip = GetOrAddAudioClip(path, type);
            Play(audioclip, type, pitch);
        }
    
        public void Play(AudioClip audioClip, Define.Sound type = Define.Sound.Effect, float pitch = 1.0f) // path로 경로를 받아주고 pitch = 소리 속도 조절
        {
            if (audioClip == null)
            {
                return;
            }
    
            if (type == Define.Sound.Bgm)
            {
                AudioSource audioSource = _audioSources[(int)Define.Sound.Bgm];
                if (audioSource.isPlaying)
                    audioSource.Stop();
    
                audioSource.pitch = pitch;
                audioSource.clip = audioClip;
                audioSource.Play();
            }
    
            else // (type == Define.Sound.Effect)
            {
                AudioSource audioSource = _audioSources[(int)Define.Sound.Effect];
                audioSource.pitch = pitch;
                audioSource.clip = audioClip;
                audioSource.PlayOneShot(audioClip);
            }
        }
    
        
        AudioClip GetOrAddAudioClip(string path, Define.Sound type = Define.Sound.Effect) // audioClip 반환하는 함수(위에 Dictionary만든 부분에서)
        {
            if (path.Contains("Sounds/") == false)
            {
                path = $"Sounds/{path}";
            }
    
            AudioClip audioClip = null;
    
            if (type == Define.Sound.Bgm)
            {
                audioClip = Managers.Resource.Load<AudioClip>(path);
            }
            else
            {
                if (_audioClips.TryGetValue(path, out audioClip) == false) // 있으면 이렇게 값을 뱉어주고 
                {
                    audioClip = Managers.Resource.Load<AudioClip>(path);
                    _audioClips.Add(path, audioClip);
                }
            }
    
            if (audioClip == null)
            {
                Debug.Log($"AudioClip Missing ! {path}");
            }
    
            return audioClip;
        }
    
    }
    
    中のコードを見て
    Init関数、Clear関数、Play、Play関数、GetOrAddAudioClip関数の5種類があります.

  • init関数は次のとおりです.
    Unityエンジンを起動すると、Rootというゲームオブジェクトが見つかります(なければ作成します).
    rootをDontDestroyOnLoadに設定し、削除できません.
    String[]SoundName=Systemで、Defineで定義されたサウンドサイズが含まれています.Enum.GetNameを作成します.
    その後forゲートを回ってsoundNamesの子供たちをaudioSourceに順番に入れ、@Soundを親に設定します.
    すなわち、Define AudioSource(Player)セクションである.声の中の子供のように作る

  • Clearg関数
    DontDestrotyOnLoadを使用してrootを作成し、audioSource[]に入れます.Sceneが移動すると音も変わります.
    これにより,配列中に数万種の音が蓄積され,=>寡婦化する.
    それを防ぐためには、Sceneが移動するときにアレイをクリーニングする関数が必要です.
    これが現在のClear関数です.

  • Play関数
    現在、Play関数には2つのバージョンがあります.
    一つはstring pathのバージョンと
    AudioClip AudioClipを受け入れる2つのバージョンに分かれています.
  • Play関数の2つのバージョンを説明する前に
    GetOrAddAudioClip関数から説明します.
    AudioClip GetOrAddAudioClip(string path, Define.Sound type = Define.Sound.Effect) // audioClip 반환하는 함수(위에 Dictionary만든 부분에서)
        {
            if (path.Contains("Sounds/") == false)
            {
                path = $"Sounds/{path}";
            }
            // 혹시나 뺴먹고 Sound를 안붙여 줬을때를 대비한 if문
    
            AudioClip audioClip = null;
    
            if (type == Define.Sound.Bgm)
            {
                audioClip = Managers.Resource.Load<AudioClip>(path);
            }
            // Bgm이라면 그대로 path를 통해 클립을 가져온다.
            
            else // effect나 다른 사운드의 경우
            {
                if (_audioClips.TryGetValue(path, out audioClip) == false) 
                // _audioClips에 TryGetValue로 해당하는 값이 있는지 없는지 확인해주고 
                // 없다면 밑에 if문 코드를 실행한다.
                {
                    audioClip = Managers.Resource.Load<AudioClip>(path);
                    _audioClips.Add(path, audioClip); // 없었던 경우니까 캐싱을 하기 위해서 _audioClips에 Add를 통해서 넣어주자.
                }
            }
    
            if (audioClip == null)
            {
                Debug.Log($"AudioClip Missing ! {path}");
            }
    
            return audioClip;
        }
    
    GetOrAddAudioClip
    path、sound type=Effectと入力した場合
    BgmならEffectのaudioClipとLoadします.
    audioClipの関数を返します.
    したがって
    public void Play(string path, Define.Sound type = Define.Sound.Effect, float pitch = 1.0f)
        {
            AudioClip audioclip = GetOrAddAudioClip(path, type);
            Play(audioclip, type, pitch);
        }
    pathを受け入れ、GetOrAddAudioClip関数にpathを渡し、audioplipに割り当てます.
    audioClipを受信するplay関数を呼び出します.
    受信audioClipのPlay関数
    public void Play(AudioClip audioClip, Define.Sound type = Define.Sound.Effect, float pitch = 1.0f) // path로 경로를 받아주고 pitch = 소리 속도 조절
        {
            if (audioClip == null)
            {
                return;
            }
    
            if (type == Define.Sound.Bgm)
            {
                AudioSource audioSource = _audioSources[(int)Define.Sound.Bgm];
                if (audioSource.isPlaying)
                    audioSource.Stop();
    
                audioSource.pitch = pitch;
                audioSource.clip = audioClip;
                audioSource.Play();
            }
    
            else // (type == Define.Sound.Effect)
            {
                AudioSource audioSource = _audioSources[(int)Define.Sound.Effect];
                audioSource.pitch = pitch;
                audioSource.clip = audioClip;
                audioSource.PlayOneShot(audioClip);
            }
        }
    パラメータで再生されるオーディオクリップの関数を再生します.
    Bgmの場合は、現在実行中のBgmを停止します.
    対応するBgmを実行します.
    audioClipがEffectならPlayOneshotで1回実行しましょう
    これで統一音声の管理は終了した.
    ありがとうございます.