基于MONO事件派发机制之SendMessage

本文介绍如何在Unity3D中结合PureMVC与Mono的事件机制设计物品系统,重点讲解NotificationCenter脚本的实现,包括事件监听与派发过程,并讨论了使用SendMessage机制的优缺点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言,需要模块划分,那么脚本之间或者对象之间的事件传递是必不可少的。

目标:在之前的一篇文章,以装备面板的设计为例子,想设计结合PureMVC + MONO的一个共同使用, 在考虑之前的一些设计想法之后,想单独基于MONO使用事件机制,来处理MONO之间的功能,来独立出MVC框架。

Unity3D 物品系统结合MVC框架设计之装备[1]http://www.unitymanual.com/thread-35823-1-1.html


最后想法是PureMVC中View部分去处理面板结果或者面板需要与其他模块交互的功能 + Mono的事件机制处理面板内部对象之间的消息传递。

1.首先这个脚本不可缺少。

[mw_shl_code=csharp,true]using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System;

public class NotificationCenter : MonoBehaviour
{
    private static NotificationCenter defaultCenter;
    public static NotificationCenter DefaultCenter()
    {
        if (!defaultCenter)
        {
            GameObject notificationObject = new GameObject("NotificationCenter");
            defaultCenter = notificationObject.AddComponent<NotificationCenter>();
            DontDestroyOnLoad(notificationObject);
        }
        return defaultCenter;
    }

    Hashtable notifications = new Hashtable();

    public void AddObserver(Component observer, String name) { AddObserver(observer, name, null); }
    public void AddObserver(Component observer, String name, object sender)
    {
        if (name == null || name == "") { Debug.Log("Null name specified for notification in AddObserver."); return; }
        if (!notifications.ContainsKey(name))
        {
            notifications[name] = new List<Component>();
        }


        List<Component> notifyList = (List<Component>)notifications[name];
        if (!notifyList.Contains(observer)) { notifyList.Add(observer); }
    }

    public void RemoveObserver(Component observer, String name)
    {
        List<Component> notifyList = (List<Component>)notifications[name]; //change from original
        if (notifyList != null)
        {
            if (notifyList.Contains(observer)) { notifyList.Remove(observer); }
            if (notifyList.Count == 0) { notifications.Remove(name); }
        }
    }

    public void PostNotification(Component aSender, String aName) { PostNotification(aSender, aName, null); }
    public void PostNotification(Component aSender, String aName, object aData) { PostNotification(new Notification(aSender, aName, aData)); }
    public void PostNotification(Notification aNotification)
    {
        if (aNotification.name == null || aNotification.name == "") { Debug.Log("Null name sent to PostNotification."); return; }


        List<Component> notifyList = (List<Component>)notifications[aNotification.name]; 
        if (notifyList == null) { Debug.Log("Notify list not found in PostNotification."); return; }

        notifyList = new List<Component>(notifyList);
        List<Component> observersToRemove = new List<Component>(); 

        foreach (Component observer in notifyList)
        {
            if (!observer)
            {
                observersToRemove.Add(observer);
            }
            else
            {
                observer.SendMessage(aNotification.name, aNotification, SendMessageOptions.DontRequireReceiver);
            }
        }

        foreach (Component observer in observersToRemove)
        {
            notifyList.Remove(observer);
        }
    }
}[/mw_shl_code]

那么来实践一下它是如何监听事件,又是如何派发事件的。

2.监听事件

如图:


public void AddObserver(Component observer, String name)
public void AddObserver(Component observer, String name, object sender)
这两个函数都是监听函数,虽然函数名字不是监听是观察者,个人习惯。

因为是使用Unity3D自带的SendMessage事件机制,所以AddObserver的参数分别为:监听的组件,监听的组件下的脚本函数名。

其外,如果obServer是this,那就这个脚本本身内的函数,如果,是其他的脚本,则是其他脚本的函数。


挂载这个脚本,即是监听了这个脚本下的test的函数。

3.派发事件


public void PostNotification(Component aSender, String aName, object aData)
这个函数的参数分别为:派发的组件,监听的字段名,派发的数据。

对于数据类型,可以使任意类型的数据,因为对于C#,他们所有类型的基类都是object。

外话:



这个地方,AddObserver函数的第三个sender变量,在该函数中没有用到,这里是添加监听对象,第一个变量是,代表监听哪个组件,第二个变量是监听组件上的函数,第三个变量由于没有用到,一开始设计是为了,监听指定哪个组件派发过来的事件(监听事件之后,只要有人派发这个事件,这里就会监听到,假如外面有一万个派发的,但是其实他的目的可能就是想过滤只接受某个组件的派发,那这里就可以起到一个过滤的作用)。这个是可以考虑拓展的。。

缺陷:
因为是使用SendMessage,所监听的事件,必须是继承MonoBehaviour,经测试,不继承是不行的,单独继承Component也不行。









总结:想必对于基于MONO下实现MVC消息机制,使用这一拓展是可以实现的。
        其实,我们可以尝试对其结构进行更改,不使用SendMessage,而使用派发Action<T>泛型事件也是可以的,PureMVC底层就是如此。

问题:
对于Unity3D自带的SendMessage来说,它的最大的诟病,是它的效率问题。对于这一问题,可以用Delegate取而代之,据网上说,Delegate的效率10倍与SendMessage。
但是并不是说不能使用SendMessage,毕竟他底层封装了反射机制,使用十分方便,只是不可频繁使用。


下一章节,将使用Delegate去实现【不基于MONO事件派发机制之Delegate】整个源码将在下一章提供。


转载请注明出处。

作者: 大帅纷纭

微博:http://weibo.com/2357191704/profile?topnav=1&wvr=6

博客:http://blog.youkuaiyun.com/dashuaifenyun1991

邮箱:bandit_empire@163.com



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值