유니티 게임 프로젝트 6주차 작업 기록

박서영·2026년 2월 27일

2월 16, 17일 작업로그

작업 로그

  1. 설정창 UI 작업
  2. 소리 설정 관련 믹서 작업
  3. SettingManager.cs 및 SoundManager.cs, SoundSettingUI.cs 작업
  4. BGM 삽입

1. 설정창 UI 작업

  • 필요한 거는 구스구스덕 참고해서 설정할 수 있는 요소들 가져옴
  • 우선은 “소리” “화면” “컨트롤” “음성” 4가지 설정 패널을 만들고, 현재는 소리 패널 UI만 작업.
  • 설정창 UI는 접속씬에서 작업하고 후에 설정 버튼이 있는 곳에 프리팹을 옮겨 붙이면 될 듯함.

  • 설정창 UI. 슬라이더 + 스크롤 뷰 정도로 구성해두긴했는데 아직 설정요소가 적어서 스크롤할 필요는 없음.
  • 소리와 화면 패널은 전환되도록 버튼에 연결함.
  • 고민은 컨트롤을 설정할 수 있게 해서 키를 전환할 수 있게하려면 아마 플레이어 움직임을 입력받는 시스템을 현재 바꿔야할 것 같아서 고민 중.

2. 소리 설정 관련 믹서 작업

  • 현재 소리는 전체 소리, 효과음 소리, 음악(BGM) 소리, UI 관련 소리, 플레이어의 소리 이렇게 5가지가 존재하기 때문에 각 소리를 다른 Audio Source로 내보내야 각각의 소리 조정이 가능함. 여기서 Mixer를 사용하게됨.
  • _Projects/Audio/ 아래에 Audio Mixer를 만들고 MainMixer를 우선 생성. 이 메인 믹서가 전체 소리를 담당하며 이 아래 그룹 요소로 다른 BGM/SFX/UI/Player 믹서들을 만들고 각 믹서들이 볼륨을 조정하는 식.
  • Master 아래에 다음처럼 그룹을 만들어주고 각 믹서들에서 볼륨을 코드에서 접근할 수 있도록 Exposed Parameter로 만들고 이름을 설정해줌. ⇒ 추후에 코드에서 접근할 때 이 이름을 사용해야함

3. SettingManager.cs 및 SoundManager.cs, SoundSettingUI.cs 작업

  • 처음에는 SettingManager.cs에서 뭔가 값을 설정하고 저장하고 해야하지 않을까했는데.. 사운드다보니 SettingManager.cs에서는 설정창을 조정하는 위주로 코드를 작성했고, 사운드값 설정은 SoundManager.cs와 SoundSettingUI.cs를 새로 만들어서 둘 사이에서 진행하도록 코드를 작성했다.

⇒ 처음에 SettingManager.cs에 작성했었는데 그러면 SettingManager.cs에 소리 외에도 추후에 작업할 디스플레이나 다른 설정 요소 관련 슬라이더나 버튼 등 엄청 많은 UI를 인스펙터에서 붙여야해서 이렇게 바꾸었다.

  • SettingPanel 자체에는 SettingManager를 붙이고, Sound Panel에 SoundSettingUI.cs를 붙여서 설정 중에 각 부분은 각각의 패널에서 돌아가도록? 일단 구성했다.

SettingManager.cs

public class SettingManager : MonoBehaviour
{
    public static SettingManager instance;

    [Header ("패널 연결")]
    [SerializeField] private GameObject soundPanel;
    [SerializeField] private GameObject displayPanel;

    private void Awake()
    {
        if (instance == null)
        {
            instance = this;
            DontDestroyOnLoad(this.gameObject);
        }
        else
        {
            Destroy(this.gameObject);
        }
    }    
}
  • 우선은 싱글톤으로 만들어줌. 그리고 씬이 전환되어도 파괴되지 않도록 코드를 작성했는데 AI는 설정이나 UI를 다루는 부분은 씬 전환 시에 파괴되지 않게 구성하지 않는 편이 좋다고해서 추후에 수정할 예정.
  • 필드로는 설정에서 버튼을 누르면 전환될 패널을 연결해주기 위해 소리 관련 설정 패널과 디스플레이 관련 설정 패널을 둠
public class SettingManager : MonoBehaviour
{
    public void OpenSoundSettings()
    {
        SoundManager.instance.UISoundPlay("ButtonClick");
        soundPanel.SetActive(true);
        displayPanel.SetActive(false);
    }

    public void OpenDisplaySettings()
    {
        SoundManager.instance.UISoundPlay("ButtonClick");
        soundPanel.SetActive(false);
        displayPanel.SetActive(true);
    }

    public void OpenSettingPanel()
    {
        SoundManager.instance.UISoundPlay("ButtonClick");
        this.gameObject.SetActive(true);
    }

    public void CloseSettingPanel()
    {
        SoundManager.instance.UISoundPlay("ButtonClick");
        this.gameObject.SetActive(false);
    }
    
}
  • 메소드는 사실 단순히 UI 관련 작업들로 구성됨. 설정창 자체를 띄우고, 없애고 하는 메소드 → 각자 관련 버튼의 OnClick() 이벤트에 연결해둠. + 설정창 안에서 클릭한 버튼에 맞게 관련 설정 요소 패널들을 띄우는 메소드.

SoundSettingUI.cs

  • UI를 다루면서 그 값을 믹서 볼륨으로 설정하는 부분의 스크립트.
public class SoundSettingUI : MonoBehaviour
{
    [Header ("텍스트 연결")]
    [SerializeField] private TextMeshProUGUI masterVolText;
    [SerializeField] private TextMeshProUGUI bgmVolText;
    [SerializeField] private TextMeshProUGUI uiVolText;
    [SerializeField] private TextMeshProUGUI sfxVolText;
    [SerializeField] private TextMeshProUGUI playerVolText;

    [Header ("슬라이더 연결")]
    [SerializeField] private Slider masterSlider;
    [SerializeField] private Slider bgmSlider;
    [SerializeField] private Slider sfxSlider;
    [SerializeField] private Slider uiSlider;
    [SerializeField] private Slider playerSlider;
  • 슬라이더 값을 수치화해서 텍스트로 보여줄 예정이기에 그 TMPro들과, 슬라이더 자체 등 UI 연결을 위한 필드를 둠.
public void OnMasterSliderChanged(float val)
    {
        SoundManager.instance.SetMasterVolume(val);
        masterVolText.text = Mathf.RoundToInt(val*100).ToString();
    }

    public void OnUISliderChanged(float val)
    {
        SoundManager.instance.SetUIVolume(val);
        uiVolText.text = Mathf.RoundToInt(val*100).ToString();
    }

    public void OnSFXSliderChanged(float val)
    {
        SoundManager.instance.SetSFXVolume(val);
        sfxVolText.text = Mathf.RoundToInt(val*100).ToString();
    }

    public void OnBGMSliderChanged(float val)
    {
        SoundManager.instance.SetBGMVolume(val);
        bgmVolText.text = Mathf.RoundToInt(val*100).ToString();
    }

    public void OnPlayerSliderChanged(float val)
    {
        SoundManager.instance.SetPlayerVolume(val);
        playerVolText.text = Mathf.RoundToInt(val*100).ToString();
    }
  • 각 슬라이더의 On Value Changed와 연결해줄 메소드들을 적음. 슬라이더는 변경사항이 생겼을 때 float 값을 자동으로 전달해주기에 매개변수로 받은 그 값을 사운드 볼륨으로 설정하는 것.
  • 변경사항이 생기면 관련 텍스트와 관련 믹서의 볼륨으로 세팅하게됨.
  • 볼륨 세팅은 SoundManager.cs 스크립트에서 진행하기에 그쪽의 instance를 통해 메소드 호출

SoundManager.cs

  • 사운드 작업을 할 때에는 설정에서 각각의 소리를 조정할 것을 염두해두지 못해서 하나의 메소드에서 모든 소리를 재생하게 두었는데… 이제 그렇지 않고 4가지가 되어서 많은 부분을 수정함.
void Start()
    {   
        //게임 시작 시 소리 초기 세팅
        LoadSettings();
    }

    //소리 재생 관련 메소드들

    public void SFXPlay(string sfxName)
    {
        if (sfxDictionary.TryGetValue(sfxName, out AudioClip clip))
        {
            sfxSource.PlayOneShot(clip);
        }
        else
        {
            Debug.Log("Audio Clip이 없음");
        }
    }

    public void UISoundPlay(string soundName)
    {
        if (sfxDictionary.TryGetValue(soundName, out AudioClip clip))
        {
            uiSource.PlayOneShot(clip);
        }
        else
        {
            Debug.Log("Audio Clip(UI) 없음");
        }
    }

    public void BGMPlay()
    {   
        Debug.Log("BGM Play 메소드 SoundManager에서 실행");
        if (sfxDictionary.TryGetValue("BGM", out AudioClip clip))
        {
            bgmSource.clip = clip;
            bgmSource.Play();
        }
    }
  • 소리 재생 관련 메소드들로 각 요소에 맞는 재생 메소드를 따로 두었고, 각 요소에 맞는 AudioSource를 통해 재생함
  • 재생 메소드가 변경되었기에 앞서 작업한 사운드 요소들 마다 요소에 맞는 재생 메소드를 호출하도록 변경해줌.
#region 소리 볼륨 설정 관련 메소드

    public void SetVolume(string paramName, float sliderVal)
    {
        //믹서 볼륨은 데시벨 단위 쓰기 때문에 로그 계산
        float vol = Mathf.Log10(Mathf.Max(0.0001f, sliderVal)) * 20;

        //paramName = 믹서에서 정한 'Exposed Parameter'의 이름이어야함
        masterMixer.SetFloat(paramName, vol);

        //데이터 저장
        PlayerPrefs.SetFloat(paramName, sliderVal);
    }

    public void LoadSettings()
    {
        string[] paramsToLoad = {"MasterVol", "BGMVol", "SFXVol", "PlayerVol", "UIVol"};
        foreach (string p in paramsToLoad)
        {
            float savedValue = PlayerPrefs.GetFloat(p, 1f);
            SetVolume(p, savedValue);
        }
    }

    public void SetMasterVolume(float val) => SetVolume("MasterVol", val);
    public void SetBGMVolume(float val) => SetVolume("BGMVol", val);
    public void SetUIVolume(float val) => SetVolume("UIVol", val);
    public void SetSFXVolume(float val) => SetVolume("SFXVol", val);
    public void SetPlayerVolume(float val) => SetVolume("PlayerVol", val);
    #endregion
  • 아래에는 볼륨 설정 관련 메소드들이 존재하고 각 요소별로 세팅을 진행함
  • 변경사항이 생기면 바로바로 해당 믹서 볼륨을 설정하는 메소드는 아래에, 후에 설정창을 열고 닫거나 할 때 저장해둔 값을 불러와 작업하기 위한 메소드는 LoadSettings()SetVolume()을 사용해서 처리.
  • 값은 처음에는 클래스에 필드로 저장해야하나 싶었는데 AI는 유니티 자체에 PlayerPrefs가 이미 존재하기(약간 printf 같이 이미 있는 라이브러리)에 거기에 저장해주면 된다고 해서 PlayerPrefs를 사용해 볼륨값을 저장하고 있음

4. BGM 삽입

  • 테스트용으로 일단 아무 노래를 BGM으로 넣어두고 loop 사용해서 재생되도록 믹서쪽에 설정.
  • 현재 로비에 들어가면 BGM 재생되도록 ReadyManager.cs 쪽의 Start() 메소드 안에 BGM 시작 메소드를 작성해두었는데…
    • 로비 밖으로 나가버려도 BGM이 계속 재생되기에 종료하는 메소드를 두어서 처리해야함 ⇒ 그런데 아직 설정창이 접속씬에만 있어서 테스트용으로 둘 것 같다…
  • 아래는 ReadyManager의 Start() 부분 코드.. BGM 재생용으로 코드 한 줄 추가하고 제대로 된 부분에서 적었는지 디버그 로그를 간단히 찍었다..
void Start()
    {
        // 방장이 씬 로딩하면 나머지 플레이어도 자동으로 따라가게 설정
        PhotonNetwork.AutomaticallySyncScene = true;
        SoundManager.instance.BGMPlay();
        Debug.Log("BGM재생");

        // 로비에 들어오면 커스텀 프로퍼티 정보들 모두 초기화
        Hashtable props = new Hashtable();
        props.Add("IsDead", false);
        props.Add("Job", "None"); // 직업 기본값은 None 추가
        props.Add("IsReady", false);
        PhotonNetwork.LocalPlayer.SetCustomProperties(props);

        // 버튼 이벤트 리스너 등록
        readyButton.onClick.AddListener(OnClickReadyButton);
        leaveButton.onClick.AddListener(OnClickLeaveButton);
        startButton.onClick.AddListener(StartGame);

        UpdateStartButtonState();
    }

2월 20, 21일 작업 로그

1. 인게임 보이스 기초 작업

인게임 보이스 구현 시 참고한 사이트

에셋 임포트: Photon Voice2

  • 포톤 관련 내용이 전부 다시 임포트되면서 변경사항이 생겨서 원래 PUN2 임포트해서 설정했던 PhotonNetworkSettings에 있는 APP ID를 다시 넣어줌

플레이어 프리팹 컴포넌트 추가

  • Speaker와 Photon Voice View 컴포넌트를 추가 → 따로 무슨 설정을 해줘야할 줄 알았는데 설정할 수 있는 요소가 지극히 적고, 스크립트를 통해서 Photon Voice View가 알아서 필요한 Recorder를 찾아주기 때문에 컴포넌트 추가만하면 됨.
  • Speaker 컴포넌트 추가시 자동으로 Audio Source도 붙음
  • 여담으로 Photon View도 필요하다고 하는데 이거는 실상 초기부터 붙여놔서 의미가 없었다

인게임씬 VoiceManager 오브젝트

  • 게임씬에서 플레이어들의 마이크에서 받아온 소리를 전달해줄 요소
  • Recorder와 PUN Voice Client 컴포넌트를 붙여줌
    • Recorder에서
      • Transmit Enable: 마이크 전달 활성화. 이걸 끄고 키면서 마이크를 껐다 키는 기능 이걸 통해서 구현 가능
      • Voice Detection: 음성 감지해서 마이크 활성화되는 부분…인데 테스트하면서 에러가 너무 많이 나서 일단 체크해제해서 진행…
    • PUN Voice Client에서
      • Primary Recorder로 Voice Manager에 있는 레코더 넣어주고 Use Primary Recorder에 체크를 해서 해당 레코더를 사용하도록 설정.
      • Don’t Destroy On Load에 체크 표시를 해둠 → 후에 로비씬으로 옮기게되면 이 부분 고려해서 작업해야할 듯 (로비에서 처음 생성하면 인게임씬에서 생성할 필요가 없지만, Audio Source에서 Spatial 값을 2D로 조정해서 거리 상관없이 들리게 해야함 + 플레이어 프리팹이 이때 생성되는게 아니라 현재 플레이어 프리팹에 붙은 스피커나 요소를 어떻게 해야할지도 고민. → 로비에서 일시적으로 Instantiate했다가 들어갈 때 새로 하거나…그래야할 것 같다고 생각…)

2. 인게임보이스 제어 스크립트 작성

VoiceController.cs 스크립트

  • UI 제어를 위한 메소드 호출 (마이크 온/오프)
  • V키 눌렀을 때 마이크 켜고 꺼지도록 작업
  • 필요에 따라 Audio Source의 Spatial 값을 조정해, 거리에 따라 들리게 하거나 거리와 무관하게 서로 소리가 들리도록 하는 메소드 작업

회고
슬슬 마무리하는 주차라 작업량이 많지는 않다. 사실 무엇보다 화면 관련 설정한 18일 작업 로그를 안써서 더 양이 적다. 당시에 남은 일들을 지금껏 팀원들이 했던 파트에 따라 2주차 분량을 나눴는데 7주차에 개인적으로 다른 일로 바쁠 수도 있어서 좀 빨리 미리 진행한 감이 있다. 그런데 일정도 사라지고, 생각보다 시간이 많이 남아서 인게임 보이스 기능을 넣고 싶어서 시도했는데 이후에 회의 때 팀원들이랑 여러번 테스트해도 이루어지지 않아서 결국 포기하고 채팅만 사용하는 방식으로 진행할 것 같다.

profile
이불 밖은 위험해.

0개의 댓글