Unity 消息发送机制 解析
该博客,只为解析,解析,解析,已经整理好,已经整理好,已经整理好。代码核心原理套用网上最流行的那一套,也是最常用游戏开发适用的消息机制。这里面加上自己的一些优化,极大的修正(哈哈),实测,没问题。万一要是出现问题,欢迎童鞋可以留言给我修正。
有童鞋可能会好奇,unity里面不是有自己的一套消息发送, 例如什么SendMessage,这...这个几乎是不能用的。
为啥不能用,看看以下是网上给的解释,自己玩玩demo还是可以用,但是实际开发,是几乎不能用的。
I:它实现的是一种伪监听者模式,利用的是反射机制。
II:SendMessage效率不高,因为每次调用的时候都会去遍历检测自身或者子节点上要调用的方法。
III:需要知道响应事件的物件,还需要一个响应函数的函数名字符串作为参数,如果我们有多个物件都要响应某个事件怎么办呢,或者我们不知道有哪些物件要响应事件怎么办呢。(前面两句话比较抽象,这句话总能看的懂吧)
(如有不理解委托,事件可以参考我的这篇帖子:https://www.cnblogs.com/u3ddjw/p/9920994.html)
1.思考
消息发送机制,也可以叫做观察者设计模式(应该是这样的)。
通俗易懂点讲,就是 一个物体发出消息,另外一个,或者几个物体可以同时接收到这一消息并作出各自不同的行为(反馈,处理)。
那么,首先,我们想到,需要什么?
I: 我们需要的是消息(实例),发送者。 消息(实例)+发送者=我们需要的消息,就能够处理任何消息。
II:怎么把这个消息发送出去(消息处理中心)。
III:发送者发送(分发)消息的行为
IV:接收消息。
换一种说法:发布-订阅模式。举例就是定报纸,你跟邮局定了报纸,邮局就会在指定时间把报纸发下来给你;中间如果你不需要报纸了,那么你就取消这个订阅,邮局就不会发给你了。
图解:

2.解析
1)具体消息
public class Notification
{
/// <summary>
/// 发送者
/// </summary>
public GameObject sender; /// <summary>
/// 消息内容
/// </summary>
public EventArgs param; /// <summary>
/// 构造函数 (初始化)
/// </summary>
///<param name="sender">通知发送者
///<param name="param">通知内容
public Notification(GameObject sender, EventArgs param)
{
this.sender = sender;
this.param = param;
}
public Notification()
{ } /// <summary>
/// 构造函数
/// </summary>
///<param name="param">
public Notification(EventArgs param)
{
this.sender = null;
this.param = param;
}
}
/// <summary>
/// 传递的消息,这个是消息类中的具体消息种类 类
/// </summary>
public class EventArgsTest : EventArgs
{
public int id;
public string name;
}
Notification是一个稍微抽象一点的消息类,要传递一个消息(类),我前面说到了,肯定是需要知道具体发送者和具体消息类的。
而具体消息类,就是后面的EventArgsTest,这个是继承于System.EventArgs,该类是自定义类,看到后面,可能会理解为什么这样继承。
2)声明一个消息的委托
public delegate void NotificationDelegate(Notification notific);
声明一个委托传递上面所说的消息类的委托,这边通俗一点来讲就是:声明一个可以传递Notification 参数的方法。至于委托的用法这里就不详诉了。
3)消息处理中心
public class NotificationCenter
{
private static NotificationCenter instance = null;
public static NotificationCenter Get()
{
if (instance == null)
{
instance = new NotificationCenter();
return instance;
}
return instance;
} private Dictionary<uint, NotificationDelegate> eventListeners
= new Dictionary<uint, NotificationDelegate>();
public void AddEventListener(uint eventKey, NotificationDelegate listener)
{
if (!HasEventListener(eventKey))
{
NotificationDelegate del = null; //定义方法
eventListeners[eventKey] = del;// 给委托变量赋值
}
eventListeners[eventKey] += listener; //注册接收者的监听
}
public void RemoveEventListener(uint eventKey,NotificationDelegate listener)
{
if (!HasEventListener(eventKey))
return;
eventListeners[eventKey] -= listener;
if (eventListeners[eventKey] == null)
{
RemoveEventListener(eventKey);
}
}
public void RemoveEventListener(uint eventKey)
{
eventListeners.Remove(eventKey);
} /// <summary>
/// 分发事件,不需要知道发送者的情况
/// </summary>
/// <param name="eventKey"></param>
/// <param name="notific"></param>
public void PostDispatchEvent(uint eventKey, Notification notific)
{
if (!HasEventListener(eventKey))
return;
// eventListeners[eventKey].Invoke(notific);
eventListeners[eventKey](notific);
} /// <summary>
/// 分发事件,需要知道发送者,具体消息的情况
/// </summary>
///<param name="eventKey">事件Key
///<param name="sender">发送者
///<param name="param">通知内容
public void PostDispatchEvent(uint eventKey, GameObject sender, EventArgs param)
{
if (!HasEventListener(eventKey))
return;
eventListeners[eventKey](new Notification(sender, param));
}
public void PostDispatchEvent(uint eventKey)
{
if (!HasEventListener(eventKey))
return;
eventListeners[eventKey](new Notification());
} /// <summary>
/// 分发事件,不需要知道任何,只需要知道发送过来消息了
/// </summary>
///<param name="eventKey">事件Key
///<param name="param">通知内容
public void PostDispatchEvent(uint eventKey, EventArgs param)
{
if (!HasEventListener(eventKey))
return;
eventListeners[eventKey](new Notification(param));
} /// <summary>
/// 是否存在指定事件的监听器
/// </summary>
public bool HasEventListener(uint eventKey)
{
return eventListeners.ContainsKey(eventKey);
}
}
该消息机制的核心,难点也就是在这里了。
首先,既然是消息处理中心,肯定是需要一个存放传递消息(上面那个声明的委托)的容器,于是声明一个
private Dictionary<uint, OnNotification> eventListeners
= new Dictionary<uint, OnNotification>();
增加,移除 传递消息(上面那个声明的委托),不就是以下代码,需要注意的是
eventListeners[eventKey] -= listener;//取消接收者的监听
eventListeners.Remove(eventKey);//移除存放在在eventListeners为eventKey的传递消息(上面那个委托)
if (!HasEventListener(eventKey))
{
eventListeners[eventKey] = listener; //注册接收者的监听
}
else
{
eventListeners[eventKey] += listener; //注册接收者的监听,这个用法,是委托的一种机制,不理解的自己去百度看看委托咋回事。
}
这样,如何存储消息做完了。
4) 发送者发送(分发)消息的行为
/// <summary>
/// 消息类型,枚举列出,调用时需要强转为uint
/// </summary>
public enum ENotificationMsgType // 消息发送的枚举值,应该转为uint型
{
ENull = , //Test
ELoadResProgress = ,
}
以上代码,写枚举,纯是为了提高代码可读性及可维护性,C#中多写枚举,少写那种莫名其妙的 int变量,真心感谢第一家公司对我的影响,保持良好的代码可读性。
EventArgsTest args = new EventArgsTest();
args.id = ;
args.name = "我是Test发送的 name 消息哦";
NotificationCenter.Get().PostDispatchEvent((uint)ENotificationMsgType.ENull, args);
// NotificationCenter.Get().PostDispatchEvent((uint)ENotificationMsgType.ENull); //我就是通知,不发送具体啥消息,也是可以的哦
这边需要理解的是 PostDispatchEvent,这个方法,这边我 写了三重重载,因为发送消息分三种情况,如注释那样
{
只需要通知发送,不需要知道发送的具体消息类型,也不需要发送者。
只需要发送具体消息类型,不需要发送者。
需要发送具体消息类型,需要发送者。
}
5)接收消息
void Awake() { NotificationCenter.Get().AddEventListener((uint)ENotificationMsgType.ENull, UpdateTest); } void OnDestroy() { NotificationCenter.Get().RemoveEventListener((uint)ENotificationMsgType.ENull, UpdateTest); } void UpdateTest(Notification e) { EventArgsTest args = e.param as EventArgsTest; if (args != null) { string strName = args.name; int strId = args.id; } }
可能你会奇怪,注册事件和移除事件为什么这样写。这是一种标准写法。
写初始(Start),结束(OnDestroy),使得每个消息拥有一个自己的生命周期。
3.另外一种版本
(2018年12月15日,补充更新,推荐使用这个版本,但是也上述比较本质都是基本一样的)
该版本来自siki学院:给出视频链接 http://www.sikiedu.com/my/course/304
该版本优势:①极大减少代码量。
②极大节省人力。
上述版本传递消息,自定义 EventArgs的子类,遇到特殊类型,声明的类的类型很多,增大了代码量,这是极大的弊端。
该版本也是我无意间看到的,感觉很不错,特来补充。
最终,如若有讲述不清,错误之处,欢迎指正。
Unity 消息发送机制 解析的更多相关文章
- Objective-C中的消息发送总结
关于OC中的消息发送的实现,在去年也看过一次,当时有点不太理解,但是今年再看却很容易理解. 我想这跟知识体系的构建有关,如果你不认识有砖.水泥等这些建筑的基本组成部分,那么我们应该很难理解建筑是怎么建 ...
- Android HandlerThread 消息循环机制之源代码解析
关于 HandlerThread 这个类.可能有些人眼睛一瞟,手指放在键盘上,然后就是一阵狂敲.立即就能敲出一段段华丽的代码: HandlerThread handlerThread = new Ha ...
- 【Azure Service Bus】 Service Bus如何确保消息发送成功,发送端是否有Ack机制
问题描述 Service Bus如何确保消息发送成功,发送端是否有Ack机制(是否有回调API告诉发送端,服务端已经收到消息)?根据对.NET发送Service Bus消息代码的分析,发送方法queu ...
- Objective-C 消息发送与转发机制原理(摘)
八面玲珑的 objc_msgSend 此函数是消息发送必经之路,但只要一提 objc_msgSend,都会说它的伪代码如下或类似的逻辑,反正就是获取 IMP 并调用: id objc_msgSend( ...
- iOS 消息转发机制
这篇博客的前置知识点是 OC 的消息传递机制,如果你对此还不了解,请先学习之,再来看这篇.这篇博客我尝试用口语的方式像讲述 PPT 一样给大家讲述这个知识点. 我们来思考一个问题,如果对象在收到无法解 ...
- iOS 消息发送与转发详解
Objective-C 是一门动态语言,它将很多静态语言在编译和链接时期做的事情,放到了运行时来处理.之所以能具备这种特性,离不开 Runtime 这个库.Runtime 很好的解决了如何在运行时期找 ...
- ActiveMQ(2)---ActiveMQ原理分析之消息发送
持久化消息和非持久化消息的发送策略 消息同步发送和异步发送 ActiveMQ支持同步.异步两种发送模式将消息发送到broker上.同步发送过程中,发送者发送一条消息会阻塞直到broker反馈一个确认消 ...
- 【XMPP】Smack源码之消息接收与解析
XmpPullParser 鉴于xmpp协议都是以xml格式来传输,因此源码中解析协议都是用到XmpPullParser来解析xml XmpPullParser很简单,先简单介绍几个比较常用的方法 / ...
- C# Socket异步实现消息发送--附带源码
前言 看了一百遍,不如动手写一遍. Socket这块使用不是特别熟悉,之前实现是公司有对应源码改改能用. 但是不理解实现的过程和步骤,然后最近有时间自己写个demo实现看看,熟悉熟悉Socket. 网 ...
随机推荐
- CentOS6.5下安装oracle11gR2
安装前须知 内存(RAM)的最小要求是 1GB,建议 2GB 及以上. 虚拟内存 swap 建议:内存为 1GB~2GB 时建议swap大小为内存大小的 1.5 倍:内存为 2GB~16GB 时建议s ...
- inux的进程-进程的概念和fork创建进程
一. 什么是进程? 初学者,可能认为程序或者一段代码就是一个进程.其实这样说是很不全面的,进程简单的说就是一个个条件. 1.需要一个代码 2.需要运行这个代码环境和资源 从下面的一段代码,我们来分析 ...
- QTP自动化测试框架课程的目标
QTP自动化测试框架课程的目标 随着技术发展演变,qtp自动化测试工具有逐渐被其他工具和技术替换的趋势,所以我们三个POPTEST合伙人决定把qtp自动化测试的一套课程开放免费,这套qtp自动化测试课 ...
- 测试开发Python培训:实现屌丝的黄色图片收藏愿望(小插曲)
男学员在学习python的自动化过程中对于爬虫很感兴趣,有些学员就想能收藏一些情色图片,供自己欣赏.作为讲师只能是满足愿望,帮助大家实现对美的追求,http://wanimal.lofter.com/ ...
- java 解压 zip 包并删除
需求是这样的, 在服务器上有 运营上传的zip 包,内容是用户的照片,我需要做的是 获取这些照片上传,并保存到 数据库. 这里面的 上传照片,保存数据库都不难,主要问题是解压zip包,和删除zip ...
- Linux查看网络端口
简单的总结一下前段时间学习Linux的成果 查看 TCP 22 端口是否打开1.列出所有端口:[root@Demon proc]# netstat -ntlpActive Internet conne ...
- TDD 中关于mock一些理解
最近在写代码的UT时case注意到: 在写某个类的test suit时,如果这个类既有组合(Composition),又有聚合关系(Aggregation). 组合关系(Composition):部分 ...
- 一款好用的jquery评分插件
一.使用说明 1.jQuery评分插件的功能: 图标显示用户评分,更美观 可实时点击,切换评分 返回用户评分,记录用户评分 实现类似下图效果 2.优点: 美观,方便 3.缺点: 只能用于jquery开 ...
- java复习(1)---java与C++区别
[系列说明]java复习系列适宜有过java学习或C++基础或了解java初步知识的人阅读,目的是为了帮助学习过java但是好久没用已经遗忘了的童鞋快速捡起来.或者教给想快速学习java的童鞋如何应用 ...
- iOS 播放GIf图, 动态效果
一.如果你集成了SDWebImage , 有一个很简单的方法 //导入sdwebImage的某个头文件 #import "UIImage+GIF.h" _bubble1.backg ...