🎮 매니저(Manager)란?
**매니저(Manager)**는 게임 개발에서 특정 시스템이나 기능을 조율하고 관리하는 역할을 수행하는 중앙 제어 클래스입니다.
🧭 매니저의 주요 역할
역할설명
| ✅ 중앙 조율자 | 여러 개별 객체나 시스템 간의 상호작용 조율 |
| 📦 데이터 관리 | 시스템의 상태를 추적하고 전달 |
| 🛠️ 생성/소멸 관리 | 객체의 생성, 소멸, 업데이트 등을 제어 |
📌 매니저의 역할과 책임
✅ 1. 관리의 역할만 수행
- 의존성 관리
예: UIManager가 모든 UI의 켜짐/꺼짐 상태를 조율 - 리소스 관리
필요한 리소스를 로드/언로드하거나 캐싱 - 이벤트 중계
시스템 간 이벤트 전달 및 수신
❌ 2. 하지 말아야 할 것들
하지 말아야 할 일이유
| 🚫 직접 기능 구현 | 비즈니스 로직은 해당 객체가 처리해야 함 |
| 🚫 세부 데이터 처리 | 세부 동작 결정은 매니저의 역할 아님 |
| 🚫 UI/객체 내부 동작 제어 | 매니저는 제어자가 아니라 관리자 |
💡 좋은 매니저 설계 원칙
🧱 1. 단일 책임 원칙 (SRP)
- 매니저는 단 하나의 관리 책임만 가져야 합니다.
예: GameManager는 게임 상태만 관리,
UI는 UIManager, 사운드는 AudioManager가 별도 담당.
🧩 2. 중앙 집중화
- 연관된 객체는 하나의 매니저에서 조율
예:- EnemyManager: 적 생성/삭제 관리
- AudioManager: 사운드 재생/정지 관리
🔄 3. 확장 가능성
- 매니저는 유연하게 확장 가능해야 합니다.
예:- 객체들을 Dictionary<string, Enemy> 형태로 관리
- 새로운 객체도 런타임에 추가 가능
🚫 잘못된 매니저 예시
public class EnemyManager : MonoBehaviour
{
public void MoveEnemies()
{
// 이동 로직
}
public void AttackEnemies()
{
// 공격 로직
}
}
- 문제점:
- 관리 책임을 벗어남
- 적 클래스의 자율성 침해
✅ 올바른 매니저 예시
✔️ 생성/소멸/상태만 담당
public class EnemyManager : MonoBehaviour
{
private List<Enemy> enemies = new List<Enemy>();
public void SpawnEnemy(Vector3 position)
{
var enemyPrefab = Resources.Load<GameObject>("EnemyPrefab");
var enemyInstance = Instantiate(enemyPrefab, position, Quaternion.identity);
enemies.Add(enemyInstance.GetComponent<Enemy>());
}
public void DestroyAllEnemies()
{
foreach (var enemy in enemies)
{
Destroy(enemy.gameObject);
}
enemies.Clear();
}
}
- 개별 적의 동작 (이동, 공격)은 Enemy 클래스 내부에서 처리.
public class Enemy : MonoBehaviour
{
public void Move()
{
// 적 이동 로직
}
public void Attack()
{
// 적 공격 로직
}
}
✅ 요약
항목매니저는 해야 함매니저는 하면 안 됨
| 관리 | ✅ | ❌ |
| 조율 | ✅ | ❌ |
| 로직 | ❌ | ✅ |
| 세부 동작 | ❌ | ✅ |
🧩 싱글턴 패턴(Singleton Pattern) 이란?
싱글턴 패턴은 클래스 인스턴스를 하나만 생성하고, 전역적으로 공유하는 디자인 패턴입니다.
주로 전역 상태 관리와 자원 관리에 사용됩니다.
✅ 싱글턴 하나만 만들 때의 장점
장점설명
| 🌐 전역적 접근 | 언제 어디서든 접근 가능 |
| 🧠 상태 관리 용이 | 하나의 인스턴스를 참조하므로 관리가 직관적 |
| 💾 자원 절약 | 메모리, 리소스를 한 인스턴스로 공유 |
✅ 싱글턴 여러 개를 만들 때의 장점
장점설명
| 🧹 책임 분리 | 각 매니저가 자신의 책임만 수행 |
| ⚙️ 유연성 | 시스템마다 맞춤 로직을 구현 가능 |
| 🚀 확장성 | 새로운 매니저를 손쉽게 추가 가능 |
⚠️ 싱글턴 하나만 만들 때의 문제점
public class GameManager : MonoBehaviour
{
public static GameManager Instance { get; private set; }
private void Awake()
{
if (Instance != null && Instance != this)
{
Destroy(gameObject);
return;
}
Instance = this;
DontDestroyOnLoad(gameObject);
}
public void StartGame() { }
public void EndGame() { }
public void UpdateUI() { }
public void ManageAudio() { }
// 너무 많은 책임을 한 클래스가 처리함
}
문제점설명
| 🏋️♂️ 과도한 책임 | 하나의 매니저가 너무 많은 것을 처리 |
| 🔗 결합도 증가 | 여러 시스템이 하나의 객체에 의존 |
| ❌ 단일 장애 지점 | 하나의 인스턴스가 실패하면 전체에 영향 |
❗ 전역적으로 하나의 매니저를 관리할 때의 문제
📌 문제점:
GameManager가 너무 많은 기능(UI, 오디오, 게임 상태 등)을 처리하게 되어 역할 분리가 불명확하고 확장성 저하.
(내용추가)
⚠️ 싱글턴 여러 개를 만들 때의 문제점
문제점설명
| ⏱ 초기화 순서 문제 | 의존 관계가 꼬일 수 있음 |
| 🌀 관리 복잡성 증가 | 책임이 겹치거나 협업이 어려워질 수 있음 |
public class GameManager : MonoBehaviour
{
public static GameManager Instance { get; private set; }
private void Awake()
{
if (Instance != null && Instance != this)
{
Destroy(gameObject);
return;
}
Instance = this;
}
public void StartGame() { }
}
public class UIManager : MonoBehaviour
{
public static UIManager Instance { get; private set; }
private void Awake()
{
if (Instance != null && Instance != this)
{
Destroy(gameObject);
return;
}
Instance = this;
}
public void UpdateUI() { }
}
public class AudioManager : MonoBehaviour
{
public static AudioManager Instance { get; private set; }
private void Awake()
{
if (Instance != null && Instance != this)
{
Destroy(gameObject);
return;
}
Instance = this;
}
public void PlaySound() { }
}
📌 문제점:
여러 매니저가 싱글턴으로 분리되면서 초기화 순서 문제, 상호작용 조율의 복잡성 발생
🔍 언제 어떤 방식이 적합한가?
상황싱글턴 하나싱글턴 여러 개
| 시스템 단순 | ✅ 적합 | ❌ 불필요 |
| 리소스 절약 필요 | ✅ 적합 | ❌ 오버킬 |
| 복잡한 시스템 구성 | ❌ 비효율 | ✅ 적합 |
| 유지보수, 확장 | ❌ 어려움 | ✅ 유리 |
| 디버깅, 최적화 | ❌ 번거로움 | ✅ 개별 처리 용이 |
🧠 결론: 어떤 구조가 더 적합한가?
- ✅ 작고 단순한 프로젝트
→ 하나의 싱글턴으로도 충분하며 효율적. - ✅ 복잡하고 구조적인 프로젝트
→ 여러 개의 싱글턴으로 각 시스템을 분리해
유지보수성과 확장성을 높이는 것이 적절.
🧱 GameManager와 하위 매니저의 역할 분리
🔹 1. 개념
- GameManager는 중앙 조율자.
- 실제 기능은 하위 매니저에게 위임.
🎯 이 구조의 이점:
- 책임 분리: 각 매니저는 자신의 역할에 집중
- 중앙 관리: 시스템 흐름은 GameManager가 조율
🔹 2. GameManager의 역할
- 시스템 초기화 및 설정 관리
- 하위 매니저의 상태 확인 / 명령 전달
- 게임의 전반적 상태 관리
(예: 시작, 일시정지, 종료 등)
🔹 3. 구조 설계
- GameManager는 다른 매니저들을 보유하고 조율
- 하위 매니저는 독립적인 기능 담당
🔹 4. 코드 구현
✅ 1) GameManager
GameManager는 하위 매니저들을 포함하고 전체 흐름을 관리합니다.
using UnityEngine; public class GameManager : MonoBehaviour { public static GameManager Instance { get; private set; } public UIManager UIManager { get; private set; } public AudioManager AudioManager { get; private set; } public EnemyManager EnemyManager { get; private set; } private void Awake() { if (Instance != null && Instance != this) { Destroy(gameObject); return; } Instance = this; DontDestroyOnLoad(gameObject); InitializeManagers(); } /// <summary> /// 하위 매니저 초기화 /// </summary> private void InitializeManagers() { UIManager = new UIManager(); AudioManager = new AudioManager(); EnemyManager = new EnemyManager(); UIManager.Initialize(); AudioManager.Initialize(); EnemyManager.Initialize(); } /// <summary> /// 게임 시작 /// </summary> public void StartGame() { Debug.Log("Game Started"); AudioManager.PlayBackgroundMusic(); UIManager.ShowMainMenu(); } /// <summary> /// 게임 종료 /// </summary> public void EndGame() { Debug.Log("Game Over"); UIManager.ShowGameOverScreen(); } }
✅ 2) 하위 매니저
각 매니저는 자기 역할에만 집중하고 독립적으로 초기화됩니다.
🎛 UIManager
public class UIManager { public void Initialize() { Debug.Log("UIManager Initialized"); } public void ShowMainMenu() { Debug.Log("Main Menu Shown"); } public void ShowGameOverScreen() { Debug.Log("Game Over Screen Shown"); } }🔊 AudioManager
public class AudioManager { public void Initialize() { Debug.Log("AudioManager Initialized"); } public void PlayBackgroundMusic() { Debug.Log("Background Music Playing"); } }👾 EnemyManager
public class EnemyManager { public void Initialize() { Debug.Log("EnemyManager Initialized"); } public void SpawnEnemy() { Debug.Log("Enemy Spawned"); } }
'내일배움캠프 - TIL > 내일배움캠프 - TIL' 카테고리의 다른 글
| 내일배움캠프 30일차 - 구조 설계 (0) | 2025.06.04 |
|---|---|
| 내일배움캠프 29일차 - 에라토스테네스의 체 (0) | 2025.05.27 |
| 내일배움캠프 27일차 - 백준, 프로그래머스 자동 깃허브 커밋, (0) | 2025.05.26 |
| 내일배움캠프 26일차 - 기획 테이블 활용 & IDE (1) | 2025.05.23 |
| 내일배움캠프 25일차 - 데이터 드리븐 (0) | 2025.05.22 |