스파르타 게임개발종합반(Unity)/TIL - 본캠프 매일 공부 기록

2024.04.16 TIL - SystemManager(매니저들 관리)

테크러너 2024. 4. 16.

SystemManager - 매니저들 관리하기

+GameManager

저희 프로젝트에서 Manager가 점점 늘어가서 팀원중 한 분이 SystemManager를 둬서 매니저들을 관리하도록 만들어보겠다고 하셨습니다.

public class SystemManager : MonoBehaviour
{
    public static SystemManager instance;

    DataManager s_DataManager = new DataManager();
    public static DataManager data { get{ return SystemManager.instance.s_DataManager; }}

    SoundManager s_SoundManager = new SoundManager();
    public static SoundManager sound { get { return SystemManager.instance.s_SoundManager; }}

    public SaveData saveData;
    public BgmType[] bgmList;

    // public SoundManager SM => instance.soundManager; // 간단하게 가져올 수 있게함
    private void Awake()
    {
        if (instance == null)
        {
            instance = this;
            s_SoundManager.Init(GetComponent<AudioSource>()); // 시스템매니저에서 사운드매니저로 AudioSource 넘김
            DontDestroyOnLoad(gameObject); // 씬을 이동해도 사운드매니저가 삭제되지 않음
        }
        else // 이미 존재할 때
        {
            Destroy(gameObject);
        }
    }

    void Start()
    {
        Application.targetFrameRate = 60; // 어떤 기기든지 1초에 60번만 계산될 수 있게끔 설정
        s_SoundManager.PlayBGM(bgmList[0]); // 인트로씬 배경음악 재생
        data.LoadToJson();
    }
}

이게 현재까지의 최종 SystemManager.cs 상태인데 튜터님들께 질문을 드리며 수정을 해나갔고 여기서 더 고쳐야할점이 있습니다.

우선 오늘 질문한 내용들을 쭉 살펴보겠습니다.

SoundManager에서 싱글톤과 MonoBehaviour을 제거하고, SystemManager가 SoundManager를 관리하는 구조로 변경

처음에는 튜터님께 구조 변경의 도움을 받으러 갔습니다.

SystemManger가 관리하는 형태로 바꾸기 위해 SoundManager를 뜯어고쳐야했습니다.

우선 싱글톤 부분은 지웠습니다.

이후에 MonoBehaviour을 지웠는데 여기서 문제가 있었습니다.

MonoBehaviour 가 없으면 GetComponent() 를 더이상 사용하지 못합니다.

그래서 SystemManager에 AudioSource 컴포넌트를 추가하고

SystemManager.cs

public SoundManager soundManager;
private void Awake()
    {
        if (instance == null)
        {
            instance = this;
            soundManager = new SoundManager();
            soundManager.Init(GetComponent<AudioSource>()); // 시스템매니저에서 사운드매니저로 AudioSource 넘김
            DontDestroyOnLoad(gameObject); // 씬을 이동해도 사운드매니저가 삭제되지 않음
        }
        else // 이미 존재할 때
        {
            Destroy(gameObject);
        }
    }

SystemManager 에서 AudioSource 컴포넌트를 GetComponent로 받아온 후 SoundManager로 넘깁니다.

SoundManager.cs

// 배경음악 이름, 클립 묶음
[System.Serializable]
public struct BgmType
{
    public string name;       // 음악 이름
    public AudioClip clip;    // 음악 클립
}

public class SoundManager
{   
    AudioSource audioSource;

    public void Init(AudioSource audioSource)
    {
        // this.audioSource : 사운드매니저의 audioSource
        // audioSource : 시스템매니저의 audioSource
        this.audioSource = audioSource;  
    }

    // 음악 재생
    public void PlayBGM(BgmType BGM)
    {
        audioSource.clip = BGM.clip;  

        audioSource.Play(); // 지속적인 재생
    }
}
this.audioSource = audioSource;

SoundManager의 audioSource시스템매니저에서 받아온 audioSource를 넣어주는 코드입니다.

이걸로 음악 클립을 재생할 수 있게 된겁니다.

SystemManager에서의 SoundManager 할당

soundManager = new SoundManager(); 는 아래의 방법 두가지 중에 언제 해주는 것이 좋은지 질문 드렸습니다.

  • 첫 번째 방법
public SoundManager soundManager;
private void Awake()
    {
        if (instance == null)
        {
            instance = this;
            soundManager = new SoundManager();
            soundManager.Init(GetComponent<AudioSource>()); // 시스템매니저에서 사운드매니저로 AudioSource 넘김
            DontDestroyOnLoad(gameObject); // 씬을 이동해도 사운드매니저가 삭제되지 않음
        }
        else // 이미 존재할 때
        {
            Destroy(gameObject);
        }
    }
  • 두 번째 방법
    SoundManager s_SoundManager = new SoundManager();
    public static SoundManager sound { get { return SystemManager.instance.s_SoundManager; }}

답변은 두 방법 모두 맞다고 하셨습니다. 다만 어떤 상황에 따라 다릅니다.

첫 번째씬이동이 거의 없는 경우프리팹을 스테이지를 켰다껐다하는 경우개발 효율성을 위해 사용하는 경우입니다.
두 번째 방법이 정석적인FM식 방법입니다. 용량이 크고 씬전환이 빈번하게 일어나는 상황에서는 이 방식이 유리합니다.

그리고 간단하고 규모가 작은 게임인 경우에는 UI, 사운드, 게임매니저 이렇게 각각 따로 생성되어도 문제가 없으나 게임의 용량이 커지면 커질수록 통합하여 관리하는 것이 좀 더 개발에 있어서 효율적입니다.
다만 SoundManager에 한해서는 추후 세분화나 그룹핑할 일이 많아질 수 있으므로 보편적으로 따로 관리하게 됩니다.

SoundManger는 SystemManager로 따로 관리하는 것이 맞는가?

이건 튜터님들의 의견들을 첨부하겠습니다.

저는 공부하는 상황이라서 여러가지 기술들을 습득해보기 위해 SystemManager를 통해 여러 매니저들을 관리하는 방법을 공부해봤는데 결론적으로는 SoundManager는 보편적으로 따로 관리를 한다고 합니다.

  • A튜터님
    • 회사마다 "네이밍컨벤션" 혹은 "코딩규약"이 존재하여 회사마다 다른 스타일이 존재하긴합니다! 그래도 보편적으로 강의나 책에 쓰인 스타일은 SoundManager 로 사운드를 따로 관리하긴 합니다, (Sound의 경우 추후 세분화나 그룹핑 할 일이 많아짐) 만약 SystemManager 가 모든 기능을 전담한다면 나중에 SuperClass가 되어버리면 유지보수의 어려움이 있을 수도 있기 때문입니다!
  • B튜터님(제가 질문드린 튜터님)
    • 맞습니다. SoundManager를 구분하여 쓰는것이 일반적이라고 언급하긴 했었고 MonoBehaviour를 안쓰는 클래스를 만들어보고 싶다고 하셔서 뭐 그럼 해보죠~식으로 진행된 것이긴 합니다ㅎㅎ!
  • C튜터님
    • Unity엔진을 활용하신다면.. 기본적으로 데이터 구조체나 외부 라이브러리가 아닌 이상 MonoBehaviour 를 상속 받는것을 권장드립니다

SystemManager 안에 있는 SoundManager를 new 할당 하지 않고 인스펙터에 띄워 사용하는 방식

또 다른 답변의 튜터님이 있으셨는데요!

새로운 방법을 알려주셔서 적어봅니다.

[System.Serializable]
public class SoundManager
{
    public AudioSource audioSource;
}
public class SystemManager : MonoBehaviour
{
    public static SystemManager instance;

    [SerializeField]
    public SoundManager soundManager;

    private void Awake()
    {
        instance = this;
    }
}

이런 방식으로 SystemManager 안에 있는 SoundManager를 new 할당 하지 않고 인스펙터에 띄워 사용하는 방식도 있습니다.

저도 시도해보긴 했었는데 SoundManager에 [System.Serializable]만 추가해서 안됐던거였습니다..

튜터님께서 알려주신 방법을 보니 SystemManager에 [SerializeField]도 추가해야 했던거였습니다.

튜터님들과 SystemManager라는 기획법을 알려주신 팀원분께 감사의 말씀드립니다:)

반응형

댓글