유니티에서 이벤트 버스(Event Bus) 패턴을 활용한 유연한 시스템 만들기
2025. 3. 29. 10:20ㆍ유니티 unity/디자인패턴
게임을 만들다 보면, 시스템 간 소통이 복잡해지는 순간이 찾아옵니다. 처음에는 단순한 함수 호출로 충분했던 의사소통이, 프로젝트가 커질수록 꼬이기 시작하죠.
- 플레이어가 아이템을 먹으면 → UI 갱신, 사운드 재생, 퀘스트 진행 업데이트?
- 적이 죽으면 → 점수 증가, 드롭 아이템 생성, 미션 조건 확인?
- 스테이지 클리어 → 저장, 씬 전환, 클리어 UI, 음악 정지?
이런 흐름을 매번 직접 연결하면 결국 시스템 간 의존도가 높아지고, 수정이 어려워지며, 디버깅도 힘들어집니다.
이 문제를 해결하기 위해 등장하는 구조가 바로 **이벤트 버스(Event Bus)**입니다.
이벤트 버스란?
이벤트 버스는 말 그대로 모든 이벤트를 중계하는 중앙 허브 역할을 하는 구조입니다.
- 이벤트를 발생시키는 쪽은 ‘버스’에 신호만 보냅니다.
- 이벤트를 듣고 싶은 쪽은 ‘버스’에서 구독합니다.
발신자와 수신자는 서로를 전혀 몰라도 됩니다. 둘 다 이벤트 버스만 알고 있으면 소통이 가능한 구조입니다.
즉, 전역적으로 사용 가능한 느슨한 이벤트 시스템을 만드는 방식입니다.
왜 옵저버 패턴보다 더 나은가요?
옵저버 패턴은 단일 객체에 여러 옵저버가 붙는 구조라면, 이벤트 버스는 게임 전체 범위의 옵저버 시스템이라고 생각하시면 됩니다.
옵저버 패턴 이벤트 버스
특정 객체에 종속됨 | 전역으로 이벤트 중계 |
주로 한 주체에 다수의 옵저버 | 다수의 주체와 다수의 수신자 |
범위가 제한적 | 범위가 광범위함 (게임 전체 이벤트 관리 가능) |
옵저버 패턴은 로컬 이벤트 처리에 적합하고, 이벤트 버스는 게임 전체의 흐름 제어나 중앙 통신 구조에 적합합니다.
유니티에서 이벤트 버스 만들기
1. 이벤트 정의 (예: GameEvent)
public class GameEvent { }
public class ItemPickedEvent : GameEvent
{
public string itemId;
public ItemPickedEvent(string id) { itemId = id; }
}
public class EnemyKilledEvent : GameEvent
{
public int enemyId;
public EnemyKilledEvent(int id) { enemyId = id; }
}
2. 이벤트 버스 클래스
public static class EventBus
{
private static Dictionary<Type, Action<GameEvent>> _eventTable = new();
public static void Subscribe<T>(Action<T> callback) where T : GameEvent
{
Type type = typeof(T);
if (!_eventTable.ContainsKey(type))
_eventTable[type] = delegate { };
_eventTable[type] += (e) => callback((T)e);
}
public static void Unsubscribe<T>(Action<T> callback) where T : GameEvent
{
Type type = typeof(T);
if (_eventTable.ContainsKey(type))
_eventTable[type] -= (e) => callback((T)e);
}
public static void Publish(GameEvent e)
{
Type type = e.GetType();
if (_eventTable.ContainsKey(type))
_eventTable[type]?.Invoke(e);
}
}
3. 사용 예시 - 아이템 획득 시 이벤트 발생
public class Item : MonoBehaviour
{
public string itemId;
public void PickUp()
{
EventBus.Publish(new ItemPickedEvent(itemId));
Destroy(gameObject);
}
}
4. 사용 예시 - UI에서 아이템 이벤트 반응
public class InventoryUI : MonoBehaviour
{
private void OnEnable()
{
EventBus.Subscribe<ItemPickedEvent>(OnItemPicked);
}
private void OnDisable()
{
EventBus.Unsubscribe<ItemPickedEvent>(OnItemPicked);
}
private void OnItemPicked(ItemPickedEvent e)
{
Debug.Log($"아이템 획득: {e.itemId}");
// UI 업데이트 로직
}
}
주의할 점
- 메모리 누수 방지: Subscribe한 이벤트는 반드시 Unsubscribe 해주셔야 합니다.
- 디버깅용 로그 추가 추천: 어떤 이벤트가 발생했고 누가 반응했는지 추적하기 쉽도록 로그 출력 구조를 함께 두는 것이 좋습니다.
- 이벤트 타입 관리: 이벤트 타입이 많아지면 체계적인 네이밍과 분류가 중요합니다.
이벤트 버스는 유니티에서 복잡한 시스템 간의 의존성을 줄이고, 전체 이벤트 흐름을 하나의 중심 축으로 모을 수 있게 도와주는 강력한 설계 패턴입니다.
단일 이벤트보다는 게임 전반의 흐름을 제어하거나, 여러 시스템이 동시에 반응해야 할 때 더욱 큰 힘을 발휘합니다.
이벤트 버스를 통해 확장성과 유지보수성이 높은 구조를 경험해보시길 추천드립니다.
'유니티 unity > 디자인패턴' 카테고리의 다른 글
유니티에서 싱글톤(Singleton) 패턴을 활용하기 (0) | 2025.03.29 |
---|---|
유니티에서 퍼사드(Facade) 패턴을 제대로 활용해보자 (0) | 2025.03.29 |
유니티에서 옵저버 패턴(Observer Pattern)을 제대로 활용해보세요 (0) | 2025.03.29 |
유니티에서 상태(State) 패턴을 제대로 활용해보기 (0) | 2025.03.29 |
유니티에서 의존성 주입(DI) 패턴을 적용하는 이유와 방법 (0) | 2025.03.29 |