unity 消息发送机制

参考自这2片文章:

https://blog.csdn.net/ff_0528/article/details/79165272 简单易懂

https://www.cnblogs.com/u3ddjw/p/6826921.html#_label0 比上一篇复杂一点点,写的很好

委托与事件:委托可以在本类或者其他类注册函数,执行函数。事件可以在本类或者其他类注册函数,但只能在本类中执行函数。

继承自MonoBehaviour的函数不能new出对象,所以相关的类都没有继承自MonoBehaviour。

主要包含以下几个类:

枚举类型:发送的是哪种类型的消息,某种类型的消息事件可以有多个(委托链)。

消息类:要发送的消息。

发送消息的类:达到条件,触发发送消息的事件,使用 “消息中心类“ 发送消息。

注册消息的类:需要提前向“消息中心类注册事件”,然后等待接受消息,做出回应。

消息中心类:被 “发送消息的类“ 调用,做出判断,将消息发动到 “注册消息的类” 那里。

思考:我们要达到的效果其实就是“发送消息的类“发送消息,“注册消息的类”做出回应。

不使用消息机制:直接在“发送消息的类“里面创建“注册消息的类”的对象,然后调用其函数就行了。

使用消息机制:即“发送消息的类“与“注册消息的类”之间加了一个 “消息中心类“作为中间人。

以下是超级简单的版本:

发送消息的类:达到条件,触发发送消息的事件,使用 “消息中心类“ 发送消息。

using UnityEngine;
public class SimpleSender : MonoBehaviour {
    void Start () {
        //使用消息机制
        SimpleInfoCenter.Instance.CallFun(SimpleType.TypeOne,new SimpleInfo(1001,new GameObject("XiaoMing")));
        //不使用消息机制
        //SinpleReceive receive = new SinpleReceive();//这里使用GetComponent<>()或者GameObject.Find()来拿到对象
        //receive.Fun(new SimpleInfo(1001, new GameObject("XiaoMing")));
    }
}

注册消息的类:需要提前向“消息中心类注册事件”,然后等待接受消息,做出回应。

using UnityEngine;
public class SinpleReceive : MonoBehaviour {
    void Awake () {
        SimpleInfoCenter.Instance.AddFun(SimpleType.TypeOne,Fun);//使用消息机制
    }
    public void Fun(SimpleInfo info)
    {
        print("info.id " + info.id);
        print("info.obj.name " + info.obj.name);
    }
}

消息中心类:被 “发送消息的类“ 调用,做出判断,将消息发动到 “注册消息的类” 那里。

using System.Collections.Generic;
using UnityEngine;

public enum SimpleType 枚举类型:发送的是哪种类型的消息,某种类型的消息事件可以有多个(委托链)。
{
    TypeOne,TypeTwo
}
public class SimpleInfo 消息类:要发送的消息。
{
    public int id;
    public GameObject obj;
    public SimpleInfo(int id,GameObject obj)
    {
        this.id = id;
        this.obj = obj;
    }
}
public class SimpleInfoCenter { 消息中心类:被 “发送消息的类“ 调用,做出判断,将消息发动到 “注册消息的类” 那里。
    public delegate void SimpleFun(SimpleInfo info);
    public static SimpleInfoCenter Instance = new SimpleInfoCenter();
    private Dictionary<SimpleType, SimpleFun> dic = new Dictionary<SimpleType, SimpleFun>();
    public void AddFun(SimpleType type,SimpleFun fun)
    {
        dic[type] = fun;
    }
    public void CallFun(SimpleType type, SimpleInfo info)
    {
        dic[type](info);
    }
}

以下是比较完整的版本,代码如下:

消息类:要发送的消息。

public class Notification {

    public GameObject sender;
    public EventArgs param;

    public Notification()
    {
    }
    public Notification(EventArgs param)
    {
        this.sender = null;
        this.param = param;
    }
    public Notification(GameObject sender,EventArgs param)
    {
        this.sender = sender;
        this.param = param;
    }

}

//这个地方不清楚为什么要这样写

public class EventArgsTest : EventArgs
{
    public int id;
    public string name;
    public EventArgsTest(int id,string name)
    {
        this.id = id;
        this.name = name;
    }
}

发送消息的类:达到条件,触发发送消息的事件,使用 “消息中心类“ 发送消息。

using System;
using UnityEngine;

public class Send : MonoBehaviour {

    // Use this for initialization
    void Start () {
        times = 0;
    }
    int times;
    // Update is called once per frame
    void Update () {
        if (Input.GetKeyDown(KeyCode.Q) && times == 0)
        {
            times = 1;
            NotificationCenter.Get().PostDispatchEvent((int)ENotificationMsgType.ELoadResProgress, new Notification(new EventArgsTest(1001, "kkkk")));
        }
        else if(Input.GetKeyUp(KeyCode.Q))
            times = 0;
    }
}

注册消息的类:需要接受消息的类。

using UnityEngine;

public class Receive : MonoBehaviour {

    // Use this for initialization
    void Awake () {
        NotificationCenter.Get().AddEventListener((int)ENotificationMsgType.ELoadResProgress, MyFun);
    }

    void OnDestroy()
    {
        NotificationCenter.Get().ERemoveEventListener((int)ENotificationMsgType.ELoadResProgress, MyFun);
        print(" destroy  ");
    }

    void MyFun(Notification notification)
    {
        print(" receive  "+((EventArgsTest)notification.param).id);
    }
}

枚举类型:发送的是哪种类型的消息,某种类型的消息事件可以有多个(委托链)。

public enum ENotificationMsgType // 消息发送的枚举值,应该转为uint型
{
    ENull = 0, //Test
    ELoadResProgress = 1,
}

消息中心类:被 “发送消息的类“ 调用,做出判断,将消息发动到 “注册消息的类” 哪里。

public class NotificationCenter
{
    private static NotificationCenter instance = null;
    public static NotificationCenter Get()
    {
        if (instance == null)
            instance = new NotificationCenter();
        return instance;
    }
    public delegate void NotificationDelegate(Notification notific);
    private Dictionary<uint, NotificationDelegate> eventListeners = new Dictionary<uint, NotificationDelegate>();
    public bool HasEventListener(uint eventKey)
    {
        if (eventListeners.ContainsKey(eventKey))
            return true;
        return false;
    }
    public void AddEventListener(uint eventKey, NotificationDelegate listener)
    {
        if (!HasEventListener(eventKey))
            eventListeners[eventKey] = listener;
        else
            eventListeners[eventKey] += listener;
    }
    public void ERemoveEventListener(uint eventKey)
    {
        eventListeners.Remove(eventKey);
    }
    public void ERemoveEventListener(uint eventKey, NotificationDelegate listener)
    {
        if (!HasEventListener(eventKey))
            return;
        eventListeners[eventKey] -= listener;
        if (eventListeners[eventKey] == null)
            ERemoveEventListener(eventKey);
    }
    public void PostDispatchEvent(uint eventKey,Notification notific)
    {
        if (!HasEventListener(eventKey))
            return;
        eventListeners[eventKey](notific);
    }
    public void PostDispatchEvent(uint eventKey, GameObject sender, EventArgs param)
    {
        if (!HasEventListener(eventKey))
            return;
        eventListeners[eventKey](new Notification(sender, param));
    }
    public void PostDispatchEvent(uint eventKey, EventArgs param)
    {
        if (!HasEventListener(eventKey))
            return;
        eventListeners[eventKey](new Notification(param));
    }

}

猜你喜欢

转载自blog.csdn.net/tran119/article/details/81166636