Preface
Event throwing and event receiving are also common decoupling methods in game development. I understand that the design mode spectator mode has similar principles, so the event system is still a very important part in a framework. The native event system is not a large system, and there is not much code. The main idea is to register and monitor.
Code
EventManager
//------------------------------------------- // Copyright © Aladdin. All rights reserved. // Homepage: http://dingxiaowei.cn/ // Author: Aladdin // Time: 2019/3/22 11:02:40 //------------------------------------------- using GF.Debug; using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Text; namespace GF.EventSystem { /// <summary> ///Message distributor /// </summary> public class EventManager { private static EventManager instance; public static EventManager Instance { get { if (null == instance) instance = new EventManager(); return instance; } set { instance = value; } } /// <summary> ///Delegation event /// </summary> /// <typeparam name="T"></typeparam> /// <param name="sender"></param> /// <param name="evt"></param> public delegate void EventHandler<T>(object sender, T evt); /// <summary> ///Register event dictionary /// </summary> public Dictionary<Type, List<object>> handlers = new Dictionary<Type, List<object>>(); /// <summary> ///Register events /// </summary> ///< typeparam name = "t" > class type < / typeparam > ///< param name = "handler" > function < / param > public void Register<T>(EventHandler<T> handler) { Debugger.Log("Registration event:" + handler.Method.Name); Register(typeof(T), handler); } private void Register<T>(Type EventType, EventHandler<T> handler) { if (!handlers.ContainsKey(EventType)) { handlers.Add(EventType, new List<object>()); } if (!handlers[EventType].Contains(handler)) { handlers[EventType].Add(handler); } } /// <summary> ///Distribute events /// </summary> /// <typeparam name="T"></typeparam> /// <param name="sender"></param> /// <param name="evt"></param> public void Publish<T>(object sender, T evt) { subscribe(null, typeof(T), evt); } /// <summary> ///Send notification event /// </summary> /// <typeparam name="T"></typeparam> /// <param name="sender"></param> /// <param name="EventType"></param> /// <param name="evt"></param> private void publish<T>(object sender, Type EventType, T evt) { if (handlers.ContainsKey(EventType)) { Debugger.Log("public event key:" + typeof(T)); //Remove all invalid events handlers[EventType].RemoveAll(delegate (object handler) { return handler == null; }); for (int i = 0; i < handlers[EventType].Count; i++) { object handler = handlers[EventType][i]; MethodInfo method = handler.GetType().GetMethod("Invoke"); method.Invoke(handler, new object[] { sender, evt }); } } else { Debugger.Log(string.Format("<color=red>Unregistered Key:{0}</color>", EventType)); } } /// <summary> ///Logout event /// </summary> ///< typeparam name = "t" > type < / typeparam > ///< param name = "handler" > register function name < / param > public void UnRegister<T>(EventHandler<T> handler) { UnRegister(typeof(T), handler); } private void UnRegister<T>(Type EventType, EventHandler<T> handler) { if (handlers.ContainsKey(EventType)) { handlers[EventType].Remove(handler); Debugger.Log("Remove Event:" + handler); if (0 == handlers[EventType].Count)//Remove the dictionary Key when the registration event is empty { handlers.Remove(EventType); } } } /// <summary> ///Clear registration event /// </summary> public void Clear() { handlers.Clear(); } } }
Use
Monitoring messages
EventManager.Instance.Register<FishRoundData>(onFrameData);
Cancel listening
EventManager.Instance.UnRegister<FishRoundData>(onFrameData);
Listen to message callback
private void onFrameData(object sender, FishRoundData data) { }
Distribution message
EventManager.Instance.Publish<FishRoundData>(this, roundData.Value);
Improvement
We can abstract the event structure we want to listen to, and then directly inherit this base class for every new message added. In this way, we can listen to the message callback as a unified method, and then force data to become a custom event structure.
Event base class GFEventArgs
/// <summary> ///The base class of the class that contains event data in the game framework. /// </summary> public abstract class GFEventArgs : EventArgs { /// <summary> ///Initializes a new instance of a class in the game framework that contains event data. /// </summary> public GFEventArgs() { } }
Game event base class
/// <summary> ///Game logic event base class. /// </summary> public abstract class GameEventArgs : GFEventArgs { }
EventManager
internal sealed class EventManager1 { private readonly List<GameEventArgs> m_EventPool; public EventManager1() { m_EventPool = new List<GameEventArgs>(); } public bool Check(int id, EventHandler<GameEventArgs> handler) { //Check event } public void Subscribe(int id, EventHandler<GameEventArgs> handler) { //Subscription message } public void Unsubscribe(int id, EventHandler<GameEventArgs> handler) { //Cancel subscription } public void Fire(object sender, GameEventArgs e) { //Put into event response queue } public void FireNow(object sender, GameEventArgs e) { //Immediate response } }
Use
Event.Subscribe(OpenUIFormSuccessEventArgs.EventId, OnOpenUIFormSuccess);
private void OnOpenUIFormSuccess(object sender, GameEventArgs e) { OpenUIFormSuccessEventArgs ne = (OpenUIFormSuccessEventArgs)e; // Determine if userData is yourself if (ne.UserData != this) { return; } Log.Debug("UI_Menu: Congratulations, you have successfully called me."); }
GFFramework address
https://github.com/dingxiaowei/GFFrameWork