use event bus

This commit is contained in:
VDH
2025-09-16 11:00:28 +07:00
parent 68eb9bd928
commit 7918cac983
6 changed files with 276 additions and 10 deletions
@@ -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 { }
+4 -4
View File
@@ -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);
}
+16
View File
@@ -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()
{
}
}
+2
View File
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: d21c02a79936b334da12ef5379524df2
+247
View File
@@ -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
}
+2
View File
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: f24ba7881ac213b4e905d525121d0a95