use event bus
This commit is contained in:
@@ -6,9 +6,6 @@ using UnityEngine.EventSystems;
|
||||
|
||||
public class Joystick : MonoBehaviour, IPointerDownHandler, IDragHandler, IPointerUpHandler
|
||||
{
|
||||
public event Action OnPointUp;
|
||||
public event Action OnPointDown;
|
||||
|
||||
public float Horizontal { get { return (snapX) ? SnapFloat(input.x, AxisOptions.Horizontal) : input.x; } }
|
||||
public float Vertical { get { return (snapY) ? SnapFloat(input.y, AxisOptions.Vertical) : input.y; } }
|
||||
public Vector2 Direction { get { return new Vector2(Horizontal, Vertical); } }
|
||||
@@ -64,7 +61,7 @@ public class Joystick : MonoBehaviour, IPointerDownHandler, IDragHandler, IPoint
|
||||
public virtual void OnPointerDown(PointerEventData eventData)
|
||||
{
|
||||
OnDrag(eventData);
|
||||
OnPointDown?.Invoke();
|
||||
EventBus.Publish(new JoystickPressEvent());
|
||||
}
|
||||
|
||||
public void OnDrag(PointerEventData eventData)
|
||||
@@ -139,7 +136,7 @@ public class Joystick : MonoBehaviour, IPointerDownHandler, IDragHandler, IPoint
|
||||
input = Vector2.zero;
|
||||
handle.anchoredPosition = Vector2.zero;
|
||||
|
||||
OnPointUp?.Invoke();
|
||||
EventBus.Publish(new JoystickRealeaseEvent());
|
||||
}
|
||||
|
||||
protected Vector2 ScreenPointToAnchoredPosition(Vector2 screenPosition)
|
||||
@@ -154,4 +151,6 @@ public class Joystick : MonoBehaviour, IPointerDownHandler, IDragHandler, IPoint
|
||||
}
|
||||
}
|
||||
|
||||
public enum AxisOptions { Both, Horizontal, Vertical }
|
||||
public enum AxisOptions { Both, Horizontal, Vertical }
|
||||
public struct JoystickPressEvent { }
|
||||
public struct JoystickRealeaseEvent { }
|
||||
@@ -144,7 +144,7 @@ public class CECHostPlayer : MonoBehaviour
|
||||
Vector3 finalMove = (move * playerSpeed) + (playerVelocity.y * Vector3.up);
|
||||
controller.Move(finalMove * Time.deltaTime);
|
||||
}
|
||||
private void JoystickRelease()
|
||||
private void JoystickRelease(JoystickRealeaseEvent joystickRealeaseEvent)
|
||||
{
|
||||
_playerStateMachine.ChangeState(_idleState);
|
||||
}
|
||||
@@ -341,11 +341,11 @@ public class CECHostPlayer : MonoBehaviour
|
||||
SetModelHostPlayer();
|
||||
Debug.LogError("Pos Character = " + pos);
|
||||
joystick = FindAnyObjectByType<Joystick>();
|
||||
joystick.OnPointUp += JoystickRelease;
|
||||
joystick.OnPointDown += JoystickStartDrag;
|
||||
EventBus.Subscribe<JoystickRealeaseEvent>(JoystickRelease);
|
||||
EventBus.Subscribe<JoystickPressEvent>(JoystickStartDrag);
|
||||
}
|
||||
|
||||
private void JoystickStartDrag()
|
||||
private void JoystickStartDrag(JoystickPressEvent joystickPressEvent)
|
||||
{
|
||||
_playerStateMachine.ChangeState(_moveState);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
using UnityEngine;
|
||||
|
||||
public class CECUIManager : MonoBehaviour
|
||||
{
|
||||
// Start is called once before the first execution of Update after the MonoBehaviour is created
|
||||
void Start()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// Update is called once per frame
|
||||
void Update()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d21c02a79936b334da12ef5379524df2
|
||||
@@ -0,0 +1,247 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Timers;
|
||||
using UnityEngine;
|
||||
|
||||
public static class EventBus
|
||||
{
|
||||
private static readonly Dictionary<Type, Delegate> globalListeners = new();
|
||||
private static readonly Dictionary<Type, Delegate> globalClassListeners = new();
|
||||
|
||||
private static readonly Dictionary<int, Dictionary<Type, Delegate>> channelListeners = new();
|
||||
private static readonly Dictionary<int, Dictionary<Type, Delegate>> channelClassListeners = new();
|
||||
|
||||
private static Timer cleanupTimer;
|
||||
|
||||
public static bool DebugEnabled = false;
|
||||
|
||||
private static void DebugLog(string message)
|
||||
{
|
||||
if (DebugEnabled)
|
||||
Console.WriteLine($"[EventBus] {message}");
|
||||
}
|
||||
|
||||
// ===== GLOBAL STRUCT EVENTS =====
|
||||
public static void Subscribe<T>(Action<T> listener) where T : struct
|
||||
{
|
||||
if (!globalListeners.ContainsKey(typeof(T)))
|
||||
globalListeners[typeof(T)] = null;
|
||||
|
||||
globalListeners[typeof(T)] = (Action<T>)globalListeners[typeof(T)] + listener;
|
||||
}
|
||||
|
||||
public static void Unsubscribe<T>(Action<T> listener) where T : struct
|
||||
{
|
||||
if (globalListeners.ContainsKey(typeof(T)))
|
||||
{
|
||||
globalListeners[typeof(T)] = (Action<T>)globalListeners[typeof(T)] - listener;
|
||||
if (globalListeners[typeof(T)] == null)
|
||||
globalListeners.Remove(typeof(T));
|
||||
}
|
||||
}
|
||||
|
||||
public static void Publish<T>(T eventData) where T : struct
|
||||
{
|
||||
if (globalListeners.TryGetValue(typeof(T), out var del) && del is Action<T> action)
|
||||
{
|
||||
DebugLog($"Publish Global Struct Event: {typeof(T).Name}");
|
||||
action.Invoke(eventData);
|
||||
}
|
||||
}
|
||||
|
||||
// ===== GLOBAL CLASS EVENTS =====
|
||||
public static void SubscribeClass<T>(Action<T> listener) where T : class
|
||||
{
|
||||
if (!globalClassListeners.ContainsKey(typeof(T)))
|
||||
globalClassListeners[typeof(T)] = null;
|
||||
|
||||
globalClassListeners[typeof(T)] = (Action<T>)globalClassListeners[typeof(T)] + listener;
|
||||
}
|
||||
|
||||
public static void UnsubscribeClass<T>(Action<T> listener) where T : class
|
||||
{
|
||||
if (globalClassListeners.ContainsKey(typeof(T)))
|
||||
{
|
||||
globalClassListeners[typeof(T)] = (Action<T>)globalClassListeners[typeof(T)] - listener;
|
||||
if (globalClassListeners[typeof(T)] == null)
|
||||
globalClassListeners.Remove(typeof(T));
|
||||
}
|
||||
}
|
||||
|
||||
public static void PublishClass<T>(T eventData) where T : class
|
||||
{
|
||||
if (globalClassListeners.TryGetValue(typeof(T), out var del) && del is Action<T> action)
|
||||
{
|
||||
DebugLog($"Publish Global Class Event: {typeof(T).Name}");
|
||||
action.Invoke(eventData);
|
||||
}
|
||||
}
|
||||
|
||||
// ===== CHANNEL STRUCT EVENTS =====
|
||||
public static void SubscribeChannel<T>(int channelId, Action<T> listener) where T : struct
|
||||
{
|
||||
if (!channelListeners.ContainsKey(channelId))
|
||||
channelListeners[channelId] = new Dictionary<Type, Delegate>();
|
||||
|
||||
if (!channelListeners[channelId].ContainsKey(typeof(T)))
|
||||
channelListeners[channelId][typeof(T)] = null;
|
||||
|
||||
channelListeners[channelId][typeof(T)] = (Action<T>)channelListeners[channelId][typeof(T)] + listener;
|
||||
}
|
||||
|
||||
public static void UnsubscribeChannel<T>(int channelId, Action<T> listener) where T : struct
|
||||
{
|
||||
if (channelListeners.ContainsKey(channelId) && channelListeners[channelId].ContainsKey(typeof(T)))
|
||||
{
|
||||
channelListeners[channelId][typeof(T)] = (Action<T>)channelListeners[channelId][typeof(T)] - listener;
|
||||
if (channelListeners[channelId][typeof(T)] == null)
|
||||
channelListeners[channelId].Remove(typeof(T));
|
||||
if (channelListeners[channelId].Count == 0)
|
||||
channelListeners.Remove(channelId);
|
||||
}
|
||||
}
|
||||
|
||||
public static void PublishChannel<T>(int channelId, T eventData) where T : struct
|
||||
{
|
||||
if (channelListeners.TryGetValue(channelId, out var listeners) &&
|
||||
listeners.TryGetValue(typeof(T), out var del) &&
|
||||
del is Action<T> action)
|
||||
{
|
||||
DebugLog($"Publish Channel Struct Event: {typeof(T).Name} to channel '{channelId}'");
|
||||
action.Invoke(eventData);
|
||||
}
|
||||
}
|
||||
|
||||
// ===== CHANNEL CLASS EVENTS =====
|
||||
public static void SubscribeChannelClass<T>(int channelId, Action<T> listener) where T : class
|
||||
{
|
||||
if (!channelClassListeners.ContainsKey(channelId))
|
||||
channelClassListeners[channelId] = new Dictionary<Type, Delegate>();
|
||||
|
||||
if (!channelClassListeners[channelId].ContainsKey(typeof(T)))
|
||||
channelClassListeners[channelId][typeof(T)] = null;
|
||||
|
||||
channelClassListeners[channelId][typeof(T)] = (Action<T>)channelClassListeners[channelId][typeof(T)] + listener;
|
||||
}
|
||||
|
||||
public static void UnsubscribeChannelClass<T>(int channelId, Action<T> listener) where T : class
|
||||
{
|
||||
if (channelClassListeners.ContainsKey(channelId) && channelClassListeners[channelId].ContainsKey(typeof(T)))
|
||||
{
|
||||
channelClassListeners[channelId][typeof(T)] = (Action<T>)channelClassListeners[channelId][typeof(T)] - listener;
|
||||
if (channelClassListeners[channelId][typeof(T)] == null)
|
||||
channelClassListeners[channelId].Remove(typeof(T));
|
||||
if (channelClassListeners[channelId].Count == 0)
|
||||
channelClassListeners.Remove(channelId);
|
||||
}
|
||||
}
|
||||
|
||||
public static void PublishChannelClass<T>(int channelId, T eventData) where T : class
|
||||
{
|
||||
if (channelClassListeners.TryGetValue(channelId, out var listeners) &&
|
||||
listeners.TryGetValue(typeof(T), out var del) &&
|
||||
del is Action<T> action)
|
||||
{
|
||||
DebugLog($"Publish Channel Class Event: {typeof(T).Name} to channel '{channelId}'");
|
||||
action.Invoke(eventData);
|
||||
}
|
||||
}
|
||||
|
||||
// ===== ONE-TIME SUBSCRIBE =====
|
||||
public static void SubscribeOnce<T>(Action<T> listener) where T : struct
|
||||
{
|
||||
Action<T> wrapper = null;
|
||||
wrapper = (data) =>
|
||||
{
|
||||
listener(data);
|
||||
Unsubscribe(wrapper);
|
||||
};
|
||||
Subscribe(wrapper);
|
||||
}
|
||||
|
||||
public static void SubscribeOnceClass<T>(Action<T> listener) where T : class
|
||||
{
|
||||
Action<T> wrapper = null;
|
||||
wrapper = (data) =>
|
||||
{
|
||||
listener(data);
|
||||
UnsubscribeClass(wrapper);
|
||||
};
|
||||
SubscribeClass(wrapper);
|
||||
}
|
||||
|
||||
public static void SubscribeOnceChannel<T>(int channelId, Action<T> listener) where T : struct
|
||||
{
|
||||
Action<T> wrapper = null;
|
||||
wrapper = (data) =>
|
||||
{
|
||||
listener(data);
|
||||
UnsubscribeChannel(channelId, wrapper);
|
||||
};
|
||||
SubscribeChannel(channelId, wrapper);
|
||||
}
|
||||
|
||||
public static void SubscribeOnceChannelClass<T>(int channelId, Action<T> listener) where T : class
|
||||
{
|
||||
Action<T> wrapper = null;
|
||||
wrapper = (data) =>
|
||||
{
|
||||
listener(data);
|
||||
UnsubscribeChannelClass(channelId, wrapper);
|
||||
};
|
||||
SubscribeChannelClass(channelId, wrapper);
|
||||
}
|
||||
|
||||
// ===== CHANNEL UTILITIES =====
|
||||
public static bool ChannelExists(int channelId)
|
||||
{
|
||||
return channelListeners.ContainsKey(channelId) || channelClassListeners.ContainsKey(channelId);
|
||||
}
|
||||
|
||||
public static void EnableAutoCleanup(float delaySeconds = 5f)
|
||||
{
|
||||
cleanupTimer = new Timer(delaySeconds * 1000);
|
||||
cleanupTimer.Elapsed += (sender, e) =>
|
||||
{
|
||||
var emptyStructChannels = channelListeners
|
||||
.Where(pair => pair.Value.Values.All(d => d == null))
|
||||
.Select(pair => pair.Key)
|
||||
.ToList();
|
||||
|
||||
foreach (var id in emptyStructChannels)
|
||||
{
|
||||
channelListeners.Remove(id);
|
||||
DebugLog($"Removed empty struct channel: {id}");
|
||||
}
|
||||
|
||||
var emptyClassChannels = channelClassListeners
|
||||
.Where(pair => pair.Value.Values.All(d => d == null))
|
||||
.Select(pair => pair.Key)
|
||||
.ToList();
|
||||
|
||||
foreach (var id in emptyClassChannels)
|
||||
{
|
||||
channelClassListeners.Remove(id);
|
||||
DebugLog($"Removed empty class channel: {id}");
|
||||
}
|
||||
};
|
||||
cleanupTimer.AutoReset = true;
|
||||
cleanupTimer.Start();
|
||||
}
|
||||
#if UNITY_EDITOR
|
||||
public static void LogAllActiveListeners()
|
||||
{
|
||||
foreach (var kv in globalListeners)
|
||||
{
|
||||
var methods = kv.Value?.GetInvocationList();
|
||||
if (methods != null && methods.Length > 0)
|
||||
{
|
||||
Debug.LogWarning($"[EventBus Leak] {kv.Key.Name} still has {methods.Length} listeners:");
|
||||
foreach (var m in methods)
|
||||
Debug.LogWarning($" - Target: {m.Target}, Method: {m.Method}");
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f24ba7881ac213b4e905d525121d0a95
|
||||
Reference in New Issue
Block a user