Unity 消息发送机制 解析

该博客,只为解析,解析,解析,已经整理好,已经整理好,已经整理好。代码核心原理套用网上最流行的那一套,也是最常用游戏开发适用的消息机制。这里面加上自己的一些优化,极大的修正(哈哈),实测,没问题。万一要是出现问题,欢迎童鞋可以留言给我修正。

有童鞋可能会好奇,unity里面不是有自己的一套消息发送, 例如什么SendMessage,这...这个几乎是不能用的。

为啥不能用,看看以下是网上给的解释,自己玩玩demo还是可以用,但是实际开发,是几乎不能用的。

I:它实现的是一种伪监听者模式,利用的是反射机制。

II:SendMessage效率不高,因为每次调用的时候都会去遍历检测自身或者子节点上要调用的方法。

III:需要知道响应事件的物件,还需要一个响应函数的函数名字符串作为参数,如果我们有多个物件都要响应某个事件怎么办呢,或者我们不知道有哪些物件要响应事件怎么办呢。(前面两句话比较抽象,这句话总能看的懂吧)

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 OnNotification(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 = 0, //Test       ELoadResProgress = 1,
    }

以上代码,写枚举,纯是为了提高代码可读性及可维护性,C#中多写枚举,少写那种莫名其妙的 int变量,真心感谢第一家公司对我的影响,保持良好的代码可读性。

      EventArgsTest args = new EventArgsTest();
        args.id = 3;
        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),使得每个消息拥有一个自己的生命周期。

  UpdateTest 为接收了消息作出了各自的行为,注意传递的参数,当然是消息类。

3.总结  先看图,再阅读代码。如果看不懂,可能委托还不是理解很明白,自己去看看委托,完全理解完委托再来看这篇帖子提升。  作为一个一直只做手游的程序员,消息发送机制真的是对于每一个游戏项目是非常基础重要的功能。
时间: 2024-11-06 19:54:39

Unity 消息发送机制 解析的相关文章

Unity内置的三套消息发送机制的应用实例

转自http://blog.sina.com.cn/s/blog_1491e52310102wuf6.html 代码简介 : [1] 实例中包含2个类文件, SendMessage.cs 和 ReceiveMessage.cs , 分别为消息发送端和消息接收端. [2] Unity内置的消息发送系统有一个很特别的地方 - 即使接收端的方法类型为 private 或者 protected, 也能够收到信息. [3] Unity内置了3套消息机制,它们分别为 1. SendMessage() 向自己

oc消息发送机制之performSelector方法的扩充

本文摘自别的博客 各种语言都有些传递函数的方法:C语言中可以使用函数指针,C++中有函数引用.仿函数和lambda,Objective-C里也有选择器(selector)和block. 不过由于iOS SDK中的大部分API都是selector的方式,所以本文就重点讲述selector了.Objective-C和我接触过的其他面向对象的语言不同,它强调消息传递,而非方法调用.因此你可以对一个对象传递任何消息,而不需要在编译期声名这些消息的处理方法. 很显然,既然编译期并不能确定方法的地址,那么运

Objective-C 消息发送与转发机制原理

消息发送和转发流程可以概括为:消息发送是 Runtime 通过 selector 快速查找 IMP 的过程,有了函数指针就可以执行对应的方法实现:消息转发是在查找 IMP 失败后执行一系列转发流程的慢速通道,如果不作转发处理,则会打日志和抛出异常. http://www.huanbohailawyer.com/e/space/?userid=52858?feed_filter=ks&lk20160609=&85 http://www.huanbohailawyer.com/e/space/

Chromium的IPC消息发送、接收和分发机制分析

由于Chromium采用多进程架构,因此会涉及到进程间通信问题.通过前面一文的学习,我们知道Browser进程在启动Render进程的过程中会建立一个以UNIX Socket为基础的IPC通道.有了IPC通道之后,接下来Browser进程与Render进程就以消息的形式进行通信.我们将这种消息称为IPC消息,以区别于线程消息循环中的消息.本文就分析Chromium的IPC消息发送.接收和分发机制. 老罗的新浪微博:http://weibo.com/shengyangluo,欢迎关注! Chrom

【Unity】线程安全的消息传输机制,仿照Cocos实现

近期用到了网络通信的方法,虽然unity可以用协程来实现异步操作,不过坑爹的队友不会用,他用的是传统的开线程的方法,这样就会出现线程安全的问题,然后现有的消息通信机制无法满足需求了,就得改了.还好我机智的看过Cocos2dx中消息机制的实现原理,顺手改了一下,下面贴源码:(源码后有解释) using System; using System.Collections; using System.Collections.Generic; using UnityEngine; /** * 消息派发类

Android HandlerThread 消息循环机制之源代码解析

关于 HandlerThread 这个类.可能有些人眼睛一瞟,手指放在键盘上,然后就是一阵狂敲.立即就能敲出一段段华丽的代码: HandlerThread handlerThread = new HandlerThread("handlerThread"); handlerThread.start(); Handler handler = new Handler(handlerThread.getLooper()){ public void handleMessage(Message

RabbitMQ消息确认机制—消息发送确认和 消息接收确认

/** * RabbitMQ消息确认机制 * 关于rabbit的生产和消费方的一些实用的操作: * producer的confirm和consumer的ack,这两者使用的模式都是用来保证数据完整性,防止数据丢失 */ /** * producer的confirm模式 * 业务场景描述: * 促销系统在做活动前,需要给用户的手机发送一条活动内容短信希望用户来参加, * 因为用户量有点大,所以通过往短信mq中插入数据方式,让短信服务来消费mq发短信: * 此时插入mq消息的服务为了保证给所有用户发

NSNotificationCenter消息通信机制介绍(KVO)

NSNotificationCenter消息通信机制介绍(KVO) 作用:NSNotificationCenter是专门供程序中不同类间的消息通信而设置的. 注册通知:即要在什么地方接受消息                [[NSNotificationCenter defaultCenter]  addObserver:self selector:@selector(mytest:) name:@" mytest" object:nil];        参数介绍:         

runtime消息转发机制

Objective-C 扩展了 C 语言,并加入了面向对象特性和 Smalltalk 式的消息传递机制.而这个扩展的核心是一个用 C 和 编译语言 写的 Runtime 库.它是 Objective-C 面向对象和动态机制的基石. Objective-C 是一个动态语言,这意味着它不仅需要一个编译器,也需要一个运行时系统来动态得创建类和对象.进行消息传递和转发.理解 Objective-C 的 Runtime 机制可以帮我们更好的了解这个语言,适当的时候还能对语言进行扩展,从系统层面解决项目中的