전의 프로젝트에서 EventManager를 사용하다, 점점 늘어나는 이벤트에 누락되거나 충돌하는 경우들이 생겨 EventDispatcher를 사용하였다.
이번 프로젝트는 네트워크 프로젝트라 더더욱 이벤트가 중요할 것이라 생각하여 다시 공부하였다.
EventDispatcher Script
using System;
using System.Collections.Generic;
using UnityEngine;
public delegate void EventHandler(short type);
public delegate void EventHandler<in T>(short type, T data);
public class EventDispatcher
{
public static readonly EventDispatcher instance = new EventDispatcher();
//생성자
private EventDispatcher() { }
public class EventHandlerListData
{
public short EventType { get; }
private readonly List<Delegate> _delegates;
public EventHandlerListData(short type) : this(type, 8)
{
}
public EventHandlerListData(short type, int size)
{
EventType = type;
_delegates = new List<Delegate>(size);
}
public void Send()
{
var len = _delegates.Count;
for (var i = 0; i < len; i++)
{
if (_delegates[i] == null)
continue;
var tEvent = (EventHandler)_delegates[i];
tEvent(EventType);
}
}
public void Send<T>(T data)
{
var len = _delegates.Count;
for (var i = 0; i < len; i++)
{
if (_delegates[i] == null)
continue;
var tEvent = (EventHandler<T>)_delegates[i];
tEvent(EventType, data);
}
}
public void Clear()
{
_delegates.Clear();
}
public void ClearNullEventHandler()
{
var len = _delegates.Count;
var newLen = 0;
for (var j = 0; j < len; j++)
{
if (_delegates[j] == null) continue;
if (newLen != j)
_delegates[newLen] = _delegates[j];
newLen++;
}
_delegates.RemoveRange(newLen, len - newLen);
}
public bool TryAdd(Delegate handler)
{
var newEvent = true;
#if DEBUG
if (_delegates.Contains(handler))
{
Debug.LogError("[Error] Repeat to add " + handler);
newEvent = false;
}
#endif
if (newEvent)
{
_delegates.Add(handler);
}
return newEvent;
}
public bool TryRemove(Delegate handler)
{
var index = _delegates.IndexOf(handler);
if (index != -1)
{
_delegates[index] = null; //원래 있던 부분
return true;
}
return false;
}
}
private readonly Dictionary<short, EventHandlerListData> _eventHandlerDic =
new Dictionary<short, EventHandlerListData>();
private readonly List<EventHandlerListData> _tempHandlerList = new List<EventHandlerListData>();
public void AddEventHandler(short type, EventHandler handler)
{
AddEventHandlerInternal(_eventHandlerDic, type, handler);
}
public void RemoveEventHandler(short type, EventHandler handler)
{
RemoveEventHandlerInternal(_eventHandlerDic, type, handler);
}
public void AddEventHandler<T>(short type, EventHandler<T> handler)
{
try
{
AddEventHandlerInternal(_eventHandlerDic, type, handler);
}
catch
{
Debug.LogError("trying to add handler error, type:" + type + " handler:" + handler);
}
}
public void RemoveEventHandler<T>(short type, EventHandler<T> handler)
{
RemoveEventHandlerInternal(_eventHandlerDic, type, handler);
}
public void SendEvent(short type)
{
var eventListeners = GetEventHandlerList(_eventHandlerDic, type, false);
eventListeners?.Send();
}
public void SendEvent<T>(short type, T msg)
{
var eventListeners = GetEventHandlerList(_eventHandlerDic, type, false);
eventListeners?.Send(msg);
}
public EventHandlerListData GetEventHandlerList(short type)
{
return _eventHandlerDic.TryGetValue(type, out var eventList) ? eventList : null;
}
public void Clear()
{
foreach (var eventData in _eventHandlerDic)
{
eventData.Value.Clear();
}
_eventHandlerDic.Clear();
}
public void PresizeHandler(short type, int size)
{
if (!_eventHandlerDic.ContainsKey(type))
{
_eventHandlerDic.Add(type, new EventHandlerListData(type, size));
}
}
public void ClearNullEventHandler()
{
var count = _tempHandlerList.Count;
if (count > 0)
{
for (var i = 0; i < count; i++)
{
var eventListeners = _tempHandlerList[i];
eventListeners.ClearNullEventHandler();
}
_tempHandlerList.Clear();
}
}
private void AddEventHandlerInternal(Dictionary<short, EventHandlerListData> dic, short type, Delegate handler)
{
var eventListeners = GetEventHandlerList(dic, type, true);
// 새로운 핸들러 추가
eventListeners?.TryAdd(handler);
}
private void RemoveEventHandlerInternal(Dictionary<short, EventHandlerListData> dic, short type,
Delegate handler)
{
var eventListeners = GetEventHandlerList(dic, type, false);
if (eventListeners == null)
return;
if (eventListeners.TryRemove(handler))
{
if (!_tempHandlerList.Contains(eventListeners))
_tempHandlerList.Add(eventListeners);
}
}
private EventHandlerListData GetEventHandlerList(Dictionary<short, EventHandlerListData> dic, short type,
bool autoCreate)
{
if (dic.TryGetValue(type, out var eventList))
return eventList;
if (autoCreate)
{
eventList = new EventHandlerListData(type);
dic.Add(type, eventList);
return eventList;
}
return null;
}
}
이벤트들을 정리한 enum 만들기
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace NHR
{
public class EventType
{
//이벤트들
public enum eEventType
{
NONE = -1,
Event_Test,
Change_Scene
}
}
}
매개변수가 없는 이벤트 초기화
//형식
EventDispatcher.instance.AddEventHandler((int)(이벤트타입Class).(enum).(eventType), new EventHandler((type) =>
{
(기능)
}));
//예시
//매개변수가 없는 이벤트 초기화
EventDispatcher.instance.AddEventHandler((int)NHR.EventType.eEventType.Change_Scene, new EventHandler((type) =>
{
Debug.Log("<color=yellow>Event_Test</color>");
}));
매개변수가 있는 이벤트 초기화
//형식
EventDispatcher.instance.AddEventHandler<(매개변수 타입)((int)(이벤트타입Class).(enum).(eventType), new EventHandler<(매개변수 타입)>((type, (매개변수)) =>
{
(기능)
}));
//예시
//eSceneType 매개변수가 있는 이벤트 초기화
EventDispatcher.instance.AddEventHandler<eSceneType>((int)NHR.EventType.eEventType.Change_Scene, new EventHandler<eSceneType>((type, scene) =>
{
Debug.Log("change Scene");
this.nowScene = scene;
this.ChangeScene(this.nowScene);
}));
이벤트 호출
//형식_매개변수X
EventDispatcher.instance.SendEvent((int)(이벤트타입Class).(enum).(eventType));
//예시_매개변수X
EventDispatcher.instance.SendEvent((int)NHR.EventType.eEventType.Change_Scene);
//형식_매개변수O
EventDispatcher.instance.SendEvent<매개변수타입>((int)(이벤트타입Class).(enum).(eventType), (매개변수));
//예시_매개변수O
EventDispatcher.instance.SendEvent<eSceneType>((int)NHR.EventType.eEventType.Change_Scene, eSceneType.Main);
'Project > <teamECHO> 4-1' 카테고리의 다른 글
[METAVERSE EXPO 2024] 4-1 프로젝트 부스 참여 후기 (0) | 2024.07.19 |
---|---|
[문제해결/PJ] PhotonView Character Customizing 동기화 문제2 (0) | 2024.07.19 |
[문제해결/PJ] PhotonNetwork를 이용하여 Photonview로 멀티 플레이어 캐릭터 커스터마이징 적용하기 (0) | 2024.06.18 |
[PJ] VR 환경에서 UI Camera 만들기 in URP (0) | 2024.06.05 |
[PJ/디자인패턴] Observer 패턴과 간단한 CharacterCustom (0) | 2024.06.02 |