最近在空闲时间准备做个小游戏,先把一些基本框架搭建好,本次记录的是消息的注册,监听和回调等

其实这些就是基于C#的委托(delegate)

第一步:定义一些委托

namespace Common.Messenger
{
public delegate void Callback();
public delegate void Callback<T>(T arg1);
public delegate void Callback<T, U>(T arg1, U arg2);
public delegate void Callback<T, U, V>(T arg1, U arg2, V arg3);
public delegate void Callback<T, U, V, W>(T arg1, U arg2, V arg3, W arg4);
public delegate void Callback<T, U, V, W, X>(T arg1, U arg2, V arg3, W arg4, X arg5);
public delegate void Callback<T, U, V, W, X, Y>(T arg1, U arg2, V arg3, W arg4, X arg5, Y arg6); public delegate T CallbackReturn<T>();
public delegate T CallbackReturn<T, U>(U arg1);
}

  用泛型的方式灵活运用各种消息处理

第二步:定义两个Message类,用于add/remove/brocast消息

namespace Common.Messenger
{
public enum MessengerMode : byte
{
DONT_REQUIRE_LISTENER,
REQUIRE_LISTENER,
}
private static internal class MessengerInternal
{
//......
}
public static class Messenger
{
//....
}
}

  

MessengerInternal类:用于存放消息类型,结构Dictionary<string,Delegate>

    static internal class MessengerInternal
{
public static Dictionary<string, Delegate> eventTable = new Dictionary<string, Delegate>();
public static readonly MessengerMode DEFAULT_MODE = MessengerMode.DONT_REQUIRE_LISTENER; public static void OnListenerAdding(string eventType, Delegate listenerBeingAdded)
{
if (!eventTable.ContainsKey(eventType))
eventTable.Add(eventType, null);
Delegate d = eventTable[eventType];
if(d!=null&&d.GetType()!=listenerBeingAdded.GetType())
throw new ListenerException(string.Format("Attempting to add listener with inconsistent signature for event type {0}. Current listeners have type {1} and listener being added has type {2}", eventType, d.GetType().Name, listenerBeingAdded.GetType().Name)); } public static void OnListenerMoving(string eventType,Delegate listenerBeingRemoved)
{
if (eventTable.ContainsKey(eventType))
{
Delegate d = eventTable[eventType];
if (d == null)
throw new ListenerException(string.Format("Attempting to remove listener with for event type {0} but current listener is null.", eventType));
else if(d.GetType()!=listenerBeingRemoved.GetType())
throw new ListenerException(string.Format("Attempting to remove listener with inconsistent signature for event type {0}. Current listeners have type {1} and listener being removed has type {2}", eventType, d.GetType().Name, listenerBeingRemoved.GetType().Name));
}
else
throw new ListenerException(string.Format("Attempting to remove listener for type {0} but Messenger doesn't know about this event type.", eventType));
} public static void OnListenerRemoved(string eventType)
{
if (eventTable[eventType] == null)
eventTable.Remove(eventType);
} public static void OnBroadcasting(string eventType, MessengerMode mode)
{
if(mode==MessengerMode.REQUIRE_LISTENER&&!eventTable.ContainsKey(eventType))
throw new MessengerInternal.BroadcastException(string.Format("Broadcasting message {0} but no listener found.", eventType));
} static public BroadcastException CreateBroadcastSignatureException(string eventType)
{
return new BroadcastException(string.Format("Broadcasting message {0} but listeners have a different signature than the broadcaster.", eventType));
} public class BroadcastException : Exception
{
public BroadcastException(string msg)
: base(msg)
{
}
}
public class ListenerException : Exception
{
public ListenerException(string msg):base(msg)
{ }
}
}

 Messenger类:Public类型,用于外界的调用,封装了AddListener/Remove/Brocast的方法

    public static class Messenger
{
private static Dictionary<string, Delegate> eventTable = MessengerInternal.eventTable; public static void AddListener(string eventType,Callback handler)
{
MessengerInternal.OnListenerAdding(eventType, handler);
eventTable[eventType] = (Callback)eventTable[eventType] + handler;
}
public static void RemoveListener(string eventType, Callback handler)
{
MessengerInternal.OnListenerMoving(eventType, handler);
eventTable[eventType] = (Callback)eventTable[eventType] - handler;
MessengerInternal.OnListenerRemoved(eventType);
}
public static void Broadcast(string eventType)
{
Broadcast(eventType, MessengerInternal.DEFAULT_MODE);
} public static void Broadcast(string eventType, MessengerMode mode)
{
MessengerInternal.OnBroadcasting(eventType, mode);
Delegate d;
if (eventTable.TryGetValue(eventType, out d))
{
Callback callback = d as Callback;
if (callback != null)
callback();
else
throw MessengerInternal.CreateBroadcastSignatureException(eventType);
}
}
}

  Messenger<T>类:含参数的扩展类

    public static class Messenger<T>
{
private static Dictionary<string, Delegate> eventTable = MessengerInternal.eventTable;
public static void AddListener(string eventType, Callback<T> handler)
{
MessengerInternal.OnListenerAdding(eventType, handler);
eventTable[eventType] = (Callback<T>)eventTable[eventType] + handler;
}
public static void RemoveListener(string eventType, Callback<T> handler)
{
MessengerInternal.OnListenerMoving(eventType, handler);
eventTable[eventType] = (Callback<T>)eventTable[eventType] - handler;
} public static void Broadcast(string eventType, T arg1)
{
Broadcast(eventType, arg1, MessengerInternal.DEFAULT_MODE);
}
public static void Broadcast(string eventType, T arg1, MessengerMode mode)
{
MessengerInternal.OnBroadcasting(eventType, mode);
Delegate d;
if (eventTable.TryGetValue(eventType,out d))
{
Callback<T> callback = d as Callback<T>;
if (callback != null)
callback(arg1);
}
else
throw MessengerInternal.CreateBroadcastSignatureException(eventType); }
}

  Messenger<T, U>:同上

举例:下面是一个消息弹窗例子

UI层调用

        void OnStartClick(GameObject go)
{
UIMessageMgr.ShowMessBox("?????", () => { Debug.Log("Success"); });
}

UIMessageMgr:

    public static void ShowMessBox(string content, Callback ok)
{
Messenger<string, Callback>.Broadcast(MessengerEventDef.ShowMessBox, content, ok);
//MessengerEventDef.ShowMessBox 是一个string,也就是Dictionary<>中的key
}

注册:

        public override void RegisterMessage()
{
Messenger<string, Callback>.AddListener(MessengerEventDef.ShowMessBox, ShowMessBox);
}

移除监听:

        public override void RemoveMessage()
{
Messenger<string, Callback>.RemoveListener(MessengerEventDef.ShowMessBox, ShowMessBox);
}

  

以上功能就是通过消息来显示提示框,使用的Message<T,U>,普通的消息可以用Message<T>

Client和Server之间的协议通信也用消息,Message<协议类>

//Message<协议类>.AddListener("这是一个字符串",回调方法)
//回调方法
//function(协议类)
//{
// 执行内容
//}
//Remove同上 //分发消息在接收到server的消息时把消息brocast
//function(协议类)
//{
// Message<协议类>.Brocast("这是一个字符串",协议类)
//}

  

 

unity-消息的注册,监听,回调的更多相关文章

  1. KestrelServer详解[1]:注册监听终结点(Endpoint)

    具有跨平台能力的KestrelServer是最重要的服务器类型.针对KestrelServer的设置均体现在KestrelServerOptions配置选项上,注册的终结点是它承载的最重要的配置选项. ...

  2. ORACLE之手动注册监听listener。alter system set local_listener="XXX"

    记录下刚刚做的一个为一个数据库(t02)配置多个监听(listener)的实验,过程有点小曲折. (1)新增两个测试的监听,listener.ora的配置内容(可纯手动编辑该文件或使用netca)如下 ...

  3. Android View转为图片保存为本地文件,异步监听回调操作结果;

    把手机上的一个View或ViewGroup转为Bitmap,再把Bitmap保存为.png格式的图片: 由于View转Bitmap.和Bitmap转图片都是耗时操作,(生成一个1M的图片大约500ms ...

  4. Android中添加监听回调接口的方法

    在Android中,我们经常会添加一些监听回调的接口供别的类来回调,比如自定义一个PopupWindow,需要让new这个PopupWindow的Activity来监听PopupWindow中的一些组 ...

  5. Android学习——动态注册监听网络变化

    新建一个BroadcastTest项目,然后修改MainActivity中的代码,如下: public class MainActivity extends AppCompatActivity { p ...

  6. android动态注册监听网络变化异常

    在使用广播接收器监听网络变化的时候,在AndroidManifest.xml中加入<user-permission android:name="android.permission.A ...

  7. clipboard 在 vue 项目中,on 事件监听回调多次执行

    clipboard 定义一个全局变量 import ClipboardJS from "clipboard"; if(clipboard){ clipboard.destroy() ...

  8. socket.io笔记二之事件监听回调函数接收一个客户端的回调函数

    //服务端 socket.on('test', function (name, fn) { console.log(name) //输出yes fn('woot'); }); //客户端 socket ...

  9. Unity中的事件监听

    Unity3D的uGUI系统的将UI可能触发的事件分为12个类型,即EventTriggerType枚举的12个值.如下图所示: 先以PointerClick为例.这个是用于某点点击事件.其他事件都可 ...

  10. javaScript学习关于常用注册监听和对象的创建

    JS 中的自定义对象(扩展内容)                     Object 形式的自定义对象                       对象的定义:                    ...

随机推荐

  1. 在Spring Boot中加载初始化数据

    文章目录 依赖条件 data.sql文件 schema.sql 文件 @sql注解 @SqlConfig 注解 在Spring Boot中加载初始化数据 在Spring Boot中,Spring Bo ...

  2. Python语言类型

    Python是一门动态解释型的强类型语言. 对这句话进行解析,语言分为动态的和静态的,编译型和解释型的,强类型的和弱类型的语言之分. 下面对三种不同维度的类型的语言进行解释: 1.编译型和解释型 差别 ...

  3. Qt之QListWidget:项目的多选与单选设置

    2019独角兽企业重金招聘Python工程师标准>>> #include "widget.h" #include <QApplication> #in ...

  4. 虚拟化VMware之虚拟机备份(1)

    之虚拟机备份() 模版:是一种开放,公用.安全的虚拟机压缩格式,通常使用的是扩展名为.ova可以在多个主流虚拟化平台下进行操作 是和 通过技术协作推出的基于磁盘的备份和恢复的新一代解决方案,可靠且易部 ...

  5. JVM调优:GC 参数

    2019独角兽企业重金招聘Python工程师标准>>> JVM调优:GC 参数 博客分类: java jvm 参考: <Memory Management in the Jav ...

  6. .html文件转换成.txt

    @ 思路 @-@ 简要 根据尖括号将文件分隔成字符串,建立一套判断字符串是否为标签的标准,若不为标签则为文本内容,存入结果文件中:   @-@ 详述 0. 建立两个哈希表: 哈希表1 unordere ...

  7. 数学--数论--Find Integer(勾股数定理)

    Problem Description people in USSS love math very much, and there is a famous math problem give you ...

  8. The Preliminary Contest for ICPC Asia Xuzhou 2019 徐州网络赛 K题 center

    You are given a point set with nn points on the 2D-plane, your task is to find the smallest number o ...

  9. 关于SPFA Bellman-Ford Dijkstra Floyd BFS最短路的共同点与区别

    关于模板什么的还有算法的具体介绍 戳我 这里我们只做所有最短路的具体分析. 那么同是求解最短路,这些算法到底有什么区别和联系: 对于BFS来说,他没有松弛操作,他的理论思想是从每一点做树形便利,那么时 ...

  10. 基本Linux命令(上)

           Linux的难点在于我们需要记忆大量的命令及参数.如有问题请批评指正,在下感激不尽.        Linux的命令都是在shell下使用的,也就是我们常说的终端(Terminal).包 ...