SRPG游戏开发(十八)第六章 基本框架 - 三 消息事件系统(Message Center)
2018-03-16 12:15
471 查看
返回目录
这里也是相同的,只是把参数分离成单独一个类。
下面介绍几种常见方式,各有利弊,你可以使用1种或几种混用。
这里只是参数,你也可以将事件名称(name)和发送者(sender)等也放入其中。
还是按需来。
就像注释中写的一样,你可以使用委托的
注销同样的,就是删除监听者(Remove Listener),代码如下。
在
但那不是一种好的方法。一般来说都是继承接口来实现。
只要继承了这个接口的类,全部都会变成处理者。
其次,你需要注册。
最后,依然是注销。
如果
你可以选择常规控制器,也可以选择Unity中的ScriptableObject方式。
如果你要使用ScriptableObject方式,只需继承
如果是动态创建,则保存
如果是使用创建好的
其次,注册也是添加进容器。
如果是使用创建好的
最后,是注销。
如果是使用创建好的
第六章 基本框架(Framework)
三 消息事件系统(Message Center)
常见的消息事件系统,无外乎注册,注销和执行三个方法。基本都是大同小异。这里也是相同的,只是把参数分离成单独一个类。
下面介绍几种常见方式,各有利弊,你可以使用1种或几种混用。
namespace DR.Book.SRPG_Dev.Framework { /// <summary> /// 消息中心。 /// 消息中心的方式比较多,你可以挑选一种或几种。 /// 这里把所有东西都放在了MessageCenter中, /// </summary> public static class MessageCenter { // TODO 参数,注册,注销 /// <summary> /// 分发Message的实现 /// </summary> /// <param name="message"></param> /// <param name="sender"></param> /// <param name="args"></param> /// <param name="messageParams"></param> private static void ExecuteMessage(string message, object sender, MessageArgs args, params object[] messageParams) { if (string.IsNullOrEmpty(message)) { Debug.LogError("[MessageCenter] Argument named 'message' is null or empty."); return; } if (sender == null) { Debug.LogError("[MessageCenter] Argument named 'sender' is null"); return; } // TODO 分发并执行消息事件 } } }
1 事件参数(MessageArgs.cs)
参数可以使用object[]类型,这里单独建出来一个类。
这里只是参数,你也可以将事件名称(name)和发送者(sender)等也放入其中。
还是按需来。
using System; namespace DR.Book.SRPG_Dev.Framework { public abstract class MessageArgs : EventArgs, IDisposable { public void Dispose() { OnDispose(); } protected virtual void OnDispose() { } } }
2 监听方式(Delegate)
使用监听的方式,常见的是委托模式。这里也是使用委托。/// <summary> /// Delegate Listener /// </summary> /// <param name="message"></param> /// <param name="sender"></param> /// <param name="messageArgs"></param> /// <param name="messageParams"></param> public delegate void MessageListener(string message, object sender, MessageArgs messageArgs, params object[] messageParams); /// <summary> /// 注册的Listener. /// 你也可以不使用List,直接使用MessageListener. /// 注册的时候用 listener += method. /// 注销的时候用 listener -= method. /// </summary> private static readonly Dictionary<string, List<MessageListener>> s_ListenerDict = new Dictionary<string, List<MessageListener>>();
就像注释中写的一样,你可以使用委托的
+=与
-=,也可以使用
List的
Add与
Remove来控制监听。
2.1 注册与注销(Add/Remove Listener)
注册其实就是添加监听者(Add Listener),代码如下。/// <summary> /// 注册Listener /// </summary> /// <param name="message"></param> /// <param name="listener"></param> public static void AddListener(string message, MessageListener listener) { if (string.IsNullOrEmpty(message)) { Debug.LogError("[MessageCenter] Argument named 'message' is null or empty."); return; } if (listener == null) { Debug.LogError("[MessageCenter] Argument named 'listener' is null."); return; } List<MessageListener> listeners; if (!s_ListenerDict.TryGetValue(message, out listeners)) { listeners = new List<MessageListener>(); s_ListenerDict.Add(message, listeners); } if (!listeners.Contains(listener)) { listeners.Add(listener); } }
注销同样的,就是删除监听者(Remove Listener),代码如下。
/// <summary> /// 注销Listener /// 如果Listener是MonoBehaviour, 你可以在OnDestroy或其它销毁Method中,加入注销. /// </summary> /// <param name="message"></param> /// <param name="listener"></param> public static void RemoveListener(string message, MessageListener listener) { if (string.IsNullOrEmpty(message)) { Debug.LogError("[MessageCenter] Argument named 'message' is null or empty."); return; } 104c3 if (listener == null) { Debug.LogError("[MessageCenter] Argument named 'listener' is null."); return; } List<MessageListener> listeners; if (!s_ListenerDict.TryGetValue(message, out listeners)) { return; } if (listeners.Remove(listener) && listeners.Count == 0) { s_ListenerDict.Remove(message); } } /// <summary> /// 注销Listeners /// </summary> /// <param name="message"></param> public static void RemoveListeners(string message) { if (string.IsNullOrEmpty(message)) { Debug.LogError("[MessageCenter] Argument named 'message' is null or empty."); return; } s_ListenerDict.Remove(message); }
2.2 执行事件(Trigger Event)
执行消息事件,也就是执行监听者。在
ExecuteMessage方法中添加。
// 分发给Listener List<MessageListener> listeners; if (s_ListenerDict.TryGetValue(message, out listeners)) { for (int i = 0; i < listeners.Count; i++) { MessageListener listener = listeners[i]; if (listener != null) { listener(message, sender, args, messageParams); } } }
3 处理者方式(Handler)
使用处理者的方式,要确定哪些是处理者,你可以建立一个基类,然后处理者全部继承自它。但那不是一种好的方法。一般来说都是继承接口来实现。
3.1 处理者接口(IMessageHandler.cs)
处理者接口,只需要一个处理事件的方法。这和Listener是一样的。namespace DR.Book.SRPG_Dev.Framework { public interface IMessageHandler { void ExecuteMessage(string message, object sender, MessageArgs messageArgs, params object[] messageParams); } }
只要继承了这个接口的类,全部都会变成处理者。
3.2 注册与注销(Register/Unregister Handler)
首先,和Listener一样,你需要一个容器保存处理者。/// <summary> /// 注册的Handler. /// 你也可以使用Dictionary<string, List<IMesageHandler>>来分类保存。 /// </summary> private static readonly List<IMessageHandler> s_Handlers = new List<IMessageHandler>();
其次,你需要注册。
/// <summary> /// 注册Handler /// </summary> /// <param name="handler"></param> public static void RegisterHandler(IMessageHandler handler) { if (handler == null) { Debug.LogError("[MessageCenter] Argument named 'handler' is null."); return; } if (!s_Handlers.Contains(handler)) { s_Handlers.Add(handler); } }
最后,依然是注销。
/// <summary> /// 注销Handler. /// 如果Handler是MonoBehaviour, 你可以在OnDestroy或其它销毁Method中,加入注销. /// </summary> /// <param name="handler"></param> public static void UnregisterHandler(IMessageHandler handler) { if (handler == null) { Debug.LogError("[MessageCenter] Argument named 'handler' is null."); return; } s_Handlers.Remove(handler); }
3.3 执行事件(Trigger Event)
使用处理者执行事件,在ExecuteMessage方法中添加。
// 分发给Handler if (s_Handlers.Count > 0) { for (int i = 0; i < s_Handlers.Count; i++) { IMessageHandler handler = s_Handlers[i]; if (handler == null) { s_Handlers.RemoveAt(i); i--; } else { handler.ExecuteMessage(message, sender, args, messageParams); } } }
如果
handler是一个
MonoBehaviour,并且在销毁它时,你忘记注销了。那么这种写法可以自动注销它。
4 控制器方式(Controller)
控制器方式常见于MVC框架中。你可以选择常规控制器,也可以选择Unity中的ScriptableObject方式。
4.1 控制器基类(ControllerBase.cs)
常规控制器如下。如果你要使用ScriptableObject方式,只需继承
ScriptableObject,其它并没有不同。
namespace DR.Book.SRPG_Dev.Framework { public abstract class MessageControllerBase { public abstract void ExecuteMessage(string message, object sender, MessageArgs messageArgs, params object[] messageParams); } }
4.2 注册与注销(Register/Unregsiter Controller)
首先,同样的,你需要一个容器保存控制器。如果是动态创建,则保存
Type。
如果是使用创建好的
ScriptableObject,则使用
Dictionary<string, MessageControllerBase>。
/// <summary> /// 注册的Controller. /// 这里使用普通的类,并使用System.Activator.CreateInstance(System.Type type)创建,并执行. /// 你也可以不用它,而使用Asset的ScriptableObject,见方法ExecuteMessage中的注释, /// 如果是动态创建的ScriptableObject,且你需要销毁它,则要使用Destroy,不要不管或赋值null。 /// </summary> private static readonly Dictionary<string, Type> s_ControllerDict = new Dictionary<string, Type>();
其次,注册也是添加进容器。
如果是使用创建好的
ScriptableObject,则在这个方法中,使用
ScriptableObject.CreateInstance()创建。
/// <summary> /// 注册Controller /// </summary> /// <typeparam name="T"></typeparam> /// <param name="message"></param> public static void RegisterController<T>(string message) where T : MessageControllerBase { if (string.IsNullOrEmpty(message)) { Debug.LogError("[MessageCenter] Argument named 'message' is null or empty."); return; } Type type = typeof(T); if (type.IsAbstract) { Debug.LogError("[MessageCenter] Type of controller is abstract."); return; } if (s_ControllerDict.ContainsKey(message)) { Debug.LogError("[MessageCenter] Type of controller is exist."); return; } s_ControllerDict.Add(message, type); }
最后,是注销。
如果是使用创建好的
ScriptableObject,则在这个方法中,使用
ScriptableObject.Destroy()销毁。
/// <summary> /// 注销Controller /// </summary> /// <param name="message"></param> public static void UnregisterController(string message) { if (string.IsNullOrEmpty(message)) { Debug.LogError("[MessageCenter] Argument named 'message' is null or empty."); return; } s_ControllerDict.Remove(message); }
4.3 执行事件(Trigger Event)
使用控制器执行事件,在ExecuteMessage方法中添加。
// 分发给Controller Type type; if (s_ControllerDict.TryGetValue(message, out type)) { MessageControllerBase controller = Activator.CreateInstance(type) as MessageControllerBase; if (controller != null) { controller.ExecuteMessage(message, sender, args, messageParams); } } /* ///// 使用已经创建好的ScriptableObject,Dictionary<string, MessageControllerBase> s_ControllerDict; // MessageControllerBase controller; // if (s_ControllerDict.TryGetValue(message, out controller)) // { // controller.ExecuteMessage(message, sender, args, messageParams); // } */ /* ///// 使用动态创建的ScriptableObject // Type assetType; // if (s_ControllerDict.TryGetValue(message, out assetType)) // { // MessageControllerBase controller = ScriptableObject.CreateInstance(assetType) as MessageControllerBase; // controller.ExecuteMessage(message, sender, args, messageParams); // ScriptableObject.Destroy(controller); // } */
5 发送事件(Send)
发送事件就只是一个外部接口。/// <summary> /// 分发Message /// </summary> /// <param name="message"></param> /// <param name="sender"></param> /// <param name="messageParams"></param> public static void Send(string message, object sender, params object[] messageParams) { ExecuteMessage(message, sender, null, messageParams); } /// <summary> /// 分发Message /// </summary> /// <param name="message"></param> /// <param name="sender"></param> /// <param name="args"></param> /// <param name="messageParams"></param> public static void Send(string message, object sender, MessageArgs args, params object[] messageParams) { ExecuteMessage(message, sender, args, messageParams); }
6 类型扩展(Type Extension)
这里类型扩展,只是让MonoBehaviour可以发送事件。
/// <summary> /// 让MonoBehaviour可以发送消息 /// </summary> /// <param name="mono"></param> /// <param name="message"></param> /// <param name="messageParams"></param> public static void SendByMessageCenter(this MonoBehaviour mono, string message, params object[] messageParams) { if (mono == null) { Debug.LogError("[MessageCenter] Type extention. Argument named 'mono' is null."); return; } ExecuteMessage(message, mono, null, messageParams); } /// <summary> /// 让MonoBehaviour可以发送消息 /// </summary> /// <param name="mono"></param> /// <param name="message"></param> /// <param name="args"></param> /// <param name="messageParams"></param> public static void SendByMessageCenter(this MonoBehaviour mono, string message, MessageArgs args, params object[] messageParams) { if (mono == null) { Debug.LogError("[MessageCenter] Type extention. Argument named 'mono' is null."); return; } ExecuteMessage(message, mono, args, messageParams); }
相关文章推荐
- SRPG游戏开发(二十二)第六章 基本框架 - 七 视图(View&UI)
- SRPG游戏开发(十九)第六章 基本框架 - 四 程序入口(Application Entry)
- SRPG游戏开发(十六)第六章 基本框架 - 一 本章简介(Introduction)
- SRPG游戏开发(十七)第六章 基本框架 - 二 单例模式(Singleton)
- 【Visual C++】游戏开发五十 浅墨DirectX教程十八 雪花飞扬:实现唯美的粒子系统
- 什么是游戏开发的实体系统框架 What is an entity system framework for game development
- Windows编程 从消息窗口到基本窗口 游戏循环窗口框架的简单实现
- 12.3pygame游戏开发框架(3):处理用户事件
- python3开发进阶-Django框架的Form表单系统和基本操作
- 【iOS-Cocos2d游戏开发之十一】使用Box2d物理系统以及在cocos2d框架添加Box2d物理系统lib包的方法
- 开发cocos2d-x 游戏 实战篇(7)之关卡系统的基本设计
- 跟着BOY学习开发cocos2d-x 游戏 实战篇(8)之 升级系统的基本设计--终结篇
- 【Cocos2d游戏开发之十一】使用Box2d物理系统以及在cocos2d框架添加Box2d物理系统lib包的方法
- 【cocos2d-x IOS游戏开发-捕鱼达人4】基本游戏框架
- 【Cocos2d游戏开发之十一】使用Box2d物理系统以及在cocos2d框架添加Box2d物理系统lib包的方法
- 【iOS-Cocos2d游戏开发之十一】使用Box2d物理系统以及在cocos2d框架添加Box2d物理系统lib包的方法
- 跟着BOY学习开发cocos2d-x 游戏 实战篇(7)之 关卡系统的基本设计
- RDIFramework.NET ━ .NET快速信息化系统开发框架 V3.0 版新增消息管理
- 【iOS-Cocos2d游戏开发之十一】使用Box2d物理系统以及在cocos2d框架添加Box2d物理系统lib包的方法
- android游戏开发框架libgdx的使用(十八)—资源加载管理AssetManager的使用