본문 바로가기
개발/Unity

Unity에서 이벤트버스(Event Bus) 패턴 활용하기

by DinoDev 2025. 10. 8.
728x90
반응형

Unity에서 게임을 개발하다 보면 여러 오브젝트가 서로 상호작용할 일이 많습니다.

예를 들어:

  • 플레이어가 공격하면 UI 체력이 줄어야 하고
  • 적이 피해를 받고 사망하면 점수 시스템이 반응해야 하고
  • 사운드 매니저가 효과음을 재생해야 하는 경우

이때 직접 참조(player.OnAttack += ui.UpdateHealth)로 연결하면,오브젝트가 많아질수록 코드가 뒤엉키고 유지보수가 어려워집니다.

여기서 이벤트버스(Event Bus) 패턴이 유용합니다.


1️⃣ 이벤트버스(Event Bus)란?

Event Bus는 이벤트를 “중앙 허브”로 모아 관리하고, 필요할 때 전달하는 패턴입니다.

즉,

  • 이벤트를 발행(Publish) 하는 오브젝트
  • 이벤트를 구독(Subscribe) 하는 오브젝트

이 둘을 직접 연결하지 않고,중앙의 Event Bus를 통해 통신하게 하는 방식입니다.

 

장점:

  • 오브젝트 간 결합도(Coupling) 최소화
  • 이벤트 추가/삭제가 쉽고, 유지보수가 간단
  • 여러 시스템에서 동일 이벤트를 동시에 처리 가능

2️⃣ 간단한 이벤트버스 구현 예제

🔹 EventBus 클래스

using System;
using System.Collections.Generic;

public static class EventBus
{
    // 타입별 이벤트 저장
    private static Dictionary<Type, Action<object>> _eventTable = new Dictionary<Type, Action<object>>();

    // 이벤트 구독
    public static void Subscribe<T>(Action<T> listener)
    {
        Type type = typeof(T);
        if (_eventTable.ContainsKey(type))
        {
            _eventTable[type] += (obj) => listener((T)obj);
        }
        else
        {
            _eventTable[type] = (obj) => listener((T)obj);
        }
    }

    // 이벤트 구독 해제
    public static void Unsubscribe<T>(Action<T> listener)
    {
        Type type = typeof(T);
        if (_eventTable.ContainsKey(type))
        {
            _eventTable[type] -= (obj) => listener((T)obj);
        }
    }

    // 이벤트 발행
    public static void Publish<T>(T eventData)
    {
        Type type = typeof(T);
        if (_eventTable.ContainsKey(type))
        {
            _eventTable[type]?.Invoke(eventData);
        }
    }
}

💡 포인트:
T 타입별로 이벤트를 구분해서 발행하고, 구독자가 타입별로 받을 수 있도록 구현했습니다.


🔹 이벤트 데이터 정의

public class PlayerDamageEvent
{
    public int Damage;
    public PlayerDamageEvent(int damage)
    {
        Damage = damage;
    }
}

public class EnemyDeadEvent
{
    public int Score;
    public EnemyDeadEvent(int score)
    {
        Score = score;
    }
}

🔹 이벤트 발행 예제 (Publisher)

 
using UnityEngine;

public class Player : MonoBehaviour
{
    public void TakeDamage(int damage)
    {
        Debug.Log($"플레이어가 {damage} 데미지 받음");
        EventBus.Publish(new PlayerDamageEvent(damage));
    }
}

🔹 이벤트 구독 예제 (Subscriber)

using UnityEngine;

public class UIManager : MonoBehaviour
{
    private void OnEnable()
    {
        EventBus.Subscribe<PlayerDamageEvent>(OnPlayerDamage);
    }

    private void OnDisable()
    {
        EventBus.Unsubscribe<PlayerDamageEvent>(OnPlayerDamage);
    }

    private void OnPlayerDamage(PlayerDamageEvent e)
    {
        Debug.Log($"UI 업데이트: 플레이어 체력 감소 {e.Damage}");
    }
}

3️⃣ 이벤트버스 패턴 사용 시 주의점

  1. 메모리 관리
    • 구독 후 반드시 해제(Unsubscribe) 필요
    • 안 하면 씬 전환 시 메모리 누수 발생 가능
  2. 디버깅 어려움
    • 이벤트가 어디서 호출되는지 추적하기 어려움
    • 로그를 적극 활용하거나 이벤트 이름/타입을 명확히 작성
  3. 고빈도 이벤트 주의
    • 프레임마다 호출되는 이벤트에는 적합하지 않음
    • Update 내에서 매번 Publish 하는 것은 피해야 함

4️⃣ 이벤트버스를 활용한 장점

느슨한 결합 Publisher와 Subscriber가 서로 몰라도 됨
재사용성 같은 이벤트를 여러 시스템에서 동시에 처리 가능
확장 용이 새 Subscriber만 추가하면 기능 확장 가능

5️⃣ 실제 게임에서의 활용 예시

  • 플레이어 공격 → 적 체력 감소 + UI 체력 감소 + 사운드 재생
  • 적 사망 → 점수 증가 + 아이템 드롭 + 사운드 재생
  • 게임 종료 → UI, 점수판, 효과음 등 여러 시스템 동시에 반응

🔑 핵심: 중앙 이벤트 버스를 통해 각 시스템을 독립적으로 연결


6️⃣ 마무리

Unity에서 이벤트버스 패턴을 사용하면:

  • 복잡한 오브젝트 간 상호작용을 간단히 관리
  • 유지보수성 높은 코드 구조를 만들 수 있습니다.

특히 큰 프로젝트나 여러 시스템이 얽힌 게임에서
상태 관리와 UI, 사운드, 점수 시스템 같은 다중 이벤트 처리가 필요할 때
이벤트버스 패턴은 매우 강력한 도구가 됩니다. 🎯

728x90
반응형