[Unity] 여러 Manager를 한 번에 관리하여 sw quality 높이기

지즈·2025년 2월 7일
0

Unity

목록 보기
7/17
post-thumbnail

게임 개발이 진행될수록 GameManager, UIManager, AudioManager... 수많은 매니저들이 생겨납니다. 각각을 따로 관리하다 보면 코드가 뒤엉키고 유지보수가 어려워지곤 합니다. 이 모든 매니저를 한 곳에서 깔끔하게 관리하는 방법에 대해 포스팅 해보겠습니다.

목차

  • Managers 클래스 생성하기
  • Managers에서 여러 Manager 클래스를 관리하기

Managers 클래스 생성하기

GameManager, UIManager, InputManager,… 등을 한 곳에서 관리하기 위해 이 Manager들을 관리하는 클래스를 Managers 라고 하겠습니다. Managers는 어디서든 편하게 접근할 수 있어야 하는데, 이를 구현하는 여러 시도들을 소개하고 가장 괜찮은 방법을 말씀드리겠습니다.

시도 1. 이름으로 찾기

코드

GameObject go = GameObject.Find("Manager"); // 씬에 존재하는 Managers 오브젝트를 찾기
Managers mg = go.GetComponent<Managers>(); // 해당 오브젝트에 부착된 스크립트 컴포넌트 받기
  • 다른 스크립트에서 Managers 클래스를 사용하기 위해, 씬에 빈 오브젝트를 생성하여 Managers 스크립트를 컴포넌트로 부착한다.
  • 스크립트로 씬에 존재하는 빈 오브젝트를 이름으로 찾고, 이 오브젝트의 스크립트 컴포넌트인 Managers를 찾아와 사용할 수 있다.

하지만 이름으로 오브젝트를 찾는 건 비용이 매우 큽니다. 각각의 스크립트에서 Managers가 필요할 때마다 이름으로 찾아와야 하므로 비추천되는 방식입니다.

시도 2. 싱글톤

코드

static Managers Instance;
public static Managers GetMg() { return Instance; }

// Start() 등에서 Instance 초기화
void Start()
{
	Instance = this;
}
 
  • 싱글톤 패턴을 이용한 방식입니다. 정적 변수로 선언되어 어디서든 접근할 수 있으며, 클래스 차원에서 공유되는 변수입니다.

이 코드에서는 씬에 여러 개의 Manager 오브젝트가 존재한다면, 정적 변수인 Instance 에 여러 개의 Manager 오브젝트가 덮어 씌워지게 됩니다. 즉, Manager , Manager(1) , Manager(2) … 중 마지막으로 Start() 를 실행한 오브젝트가 Instance 에 자신을 대입하게 됩니다.

시도 3. 이름으로 찾기 + 싱글톤

코드

static Managers Instance;
public static Managers GetMg() { return Instance; }

void Start()
{
	GameObject go = GameObject.Find("Manager"); // 씬에서 이름으로 오브젝트를 찾기
	Instance = go.GetComponent<Managers>();
}

씬에서 Manager 오브젝트를 찾은 뒤, 정적 변수인 InstanceManagers 컴포넌트를 넣어줍니다. 씬에 여러 개의 Manager 가 있더라도 첫 번째 오브젝트를 찾아오기 때문에, 덮어 씌워지는 문제가 줄어들 수 있습니다.

그러나, 씬에 Manager 오브젝트가 없다면 null을 반환하여, NullReferenceException이 발생하게 됩니다. null인지 확인하는 절차를 추가해줘야 합니다.

시도 4. 최종

이 코드에서는 s_instance에 접근하기 전 null 인지 확인합니다. 만약 s_instance에 오브젝트가 할당된 상태가 아니라면 씬에서 Manager 오브젝트를 찾아와 s_instance에 오브젝트를 할당해줍니다. 심지어, 씬 상에 Manager 가 존재하지 않았다면 Manager를 생성하고 Managers 스크립트를 컴포넌트로 부착해주며 오류 가능성을 차단합니다.

static Manager s_instance;
public static Manager Instance
{ 
	get
	{
		Init();
		return s_instance;
	}
}

void Start()
{
	Init();
}

static void Init()
{
	if (s_instance == null)
	{
		GameObject go = GameObject.Find("Manager");
		if (go == null) 
		{
			go = new GameObject { name = "Manager" }; // "Manager" 이름의 오브젝트 생성
			go.AddComponent<Managers>(); // Managers 스크립트를 컴포넌트로 부착  
		}
	
		DontDestroyOnLoad(go);
		s_instance = go.GetComponent<Managers>();
	}
}

지금까지 Managers 클래스 초기화와 생성하는 부분을 작성해봤습니다. 이제 이 클래스에서 다양한 ~~~ Manager 들을 어떻게 관리할지 얘기하겠습니다.

여러 Manager를 관리하기

InputManagerResourceManager 가 필요하다고 가정합니다. 이 클래스 다이어그램에서 Managers는 여러 ~Manager 들을 private 변수로 갖고, 다른 클래스에서 프로퍼티를 통해 접근할 수 있게 하고 있습니다. 이를 통해, 모든 스크립트에서 Managers.Input 과 같이 접근하여 매니저들의 기능을 이용할 수 있게 됩니다.

예시 코드

// PlayerController.cs

void SomeMethod()
{
	Managers.Input.OnKeyUpdate(); // InputManager의 OnKeyUpdate()을 사용한다.
	Managers.Resource.Instantiate(); // ResouceManager의 Instactiate()을 사용한다.
}

여러 매니저들을 한 곳에서 관리한다면 코드의 유지보수성을 높일 수 있습니다. 예를 들어 플레이어의 입력을 감지하는 InputManager의 경우, ManagersUpdate() 에서 키 입력이 있는지를 판별하고 입력 발생 시 이를 이벤트로 알린다면, 입력 감지가 필요한 모든 클래스는 입력을 감지하는 로직을 작성할 필요가 없게 됩니다. 이에 대해서는 다른 포스팅으로 더 자세히 말씀드리겠습니다.

여러 Manager 클래스들을 관리하는 Managers 클래스의 작성 방법과 관리 방법에 대해 알아봤습니다. 이상으로 포스팅 마치겠습니다.

profile
클라이언트 개발자가 되는 그 날까지 킵 고잉

0개의 댓글