| 씬 전체에서 MonoBehaviour를 상속해 싱글톤처럼 관리하면서도 성능 최적화된 버전으로 만들어 보겠습니다. 특징은 다음과 같습니다.
MonoBehaviour를 상속 했기 때문에, Update, Coroutine 기능 활용 가능 1. EventBus 구현 EventBus.cs 파일 using System;
using System.Collections.Generic; using UnityEngine; public class EventBus : MonoBehaviour { private static EventBus _instance; private static bool _isQuitting = false; public static EventBus Instance { get { if (_isQuitting) return null; // 종료 중에는 생성 금지 if (_instance == null) { var go = new GameObject("EventBus"); _instance = go.AddComponent<EventBus>(); DontDestroyOnLoad(go); } return _instance; } } private void OnApplicationQuit() { _isQuitting = true; } private class Subscription { public WeakReference TargetRef; public Delegate Callback; } private readonly Dictionary<Type, List<Subscription>> events = new(); #region Subscribe / Unsubscribe public void Subscribe<T>(MonoBehaviour subscriber, Action<T> callback) { if (subscriber == null || callback == null) throw new ArgumentNullException(); var type = typeof(T); if (!events.TryGetValue(type, out var list)) { list = new List<Subscription>(); events[type] = list; } list.Add(new Subscription { TargetRef = new WeakReference(subscriber), Callback = callback }); } public void Unsubscribe<T>(MonoBehaviour subscriber, Action<T> callback) { if (subscriber == null || callback == null) return; var type = typeof(T); if (!events.TryGetValue(type, out var list)) return; list.RemoveAll(sub => (object)sub.TargetRef.Target == subscriber && sub.Callback == (Delegate)callback ); if (list.Count == 0) events.Remove(type); } #endregion #region Publish public void Publish<T>(T evt) { var type = typeof(T); if (!events.TryGetValue(type, out var list)) return; for (int i = list.Count - 1; i >= 0; i--) { var sub = list[i]; if (sub.TargetRef.IsAlive) { ((Action<T>)sub.Callback)?.Invoke(evt); } else { list.RemoveAt(i); // 이미 파괴된 구독자 제거 } } if (list.Count == 0) events.Remove(type); } #endregion } 2. Event 정의 PlayerScoreEvent.cs 파일 public class PlayerScoredEvent
{ public int Score { get; private set; } public PlayerScoredEvent(int score) { Score = score; } } 3. 이벤트 구독 ScoreManager.cs 파일 using UnityEngine;
public class ScoreManager : MonoBehaviour { void OnEnable() { EventBus.Instance.Subscribe<PlayerScoredEvent>(this, OnPlayerScored); } void OnDisable() { EventBus.Instance?.Unsubscribe<PlayerScoredEvent>(this, OnPlayerScored); } void OnPlayerScored(PlayerScoredEvent e) { Debug.Log("EventBus: Score: " + e.Score); } } 4. 이벤트 발행 EventBus.Instance.Publish(new PlayerScoredEvent(10));
|