优化后Unity可传参的EventManager消息管理类,采用订阅者/发布者模式

分享一个消息发送及接收的框架,改编至一个叫EventManager的消息管理类(https://unity3d.com/cn/learn/tutorials/topics/scripting/events-creating-simple-messaging-system),之前在寻找消息管理框架的时候发现了这个类,感觉挺好用,逻辑也很清晰。但随着需求的增加,发现它也有些许的局限性,不能传参,只能触发事件,于是自己在上面做了些扩展。它的核心思想是通过字典来管理方法及方法触发的条件,

private Dictionary <string, UnityEvent> eventDictionary;

 string表示存入的消息名,unityEvent存入的消息名所对应的事件,unityEvent本身是一个不带参的委托,因此导致我们调用的时候不能传参。于是我把unityEvent换成了Action,这样就可以存带参的方法了,如Action<int>,Action<string>等等。但问题又来了,一个项目肯定要传多种参数,我到底是要用Action<int>,还是要用Action<string>,还是都要呢,多种参数怎么传呢?用列表保存!于是我选用了ArrayList,没有使用List,因为List需指定泛型,这样限制了我们传参的种类。

 private Dictionary <string, Action<ArrayList>> eventDictionary;

因为项目赶时间,没来得及细化,若有不足之处,欢迎指证,下面给出代码:

消息管理类(挂在场景中任意物体上)

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class MSGCenter : MonoBehaviour {


    private Dictionary<string, Action<ArrayList>> eventDictionary;

    private static MSGCenter eventManager;
    //单例
    public static MSGCenter instance
    {
        get
        {
            if (!eventManager)
            {
                //在Unity的Hierarchy中必须有一个名为EventManager的空物体,并挂上EventManager脚本
                eventManager = FindObjectOfType(typeof(MSGCenter)) as MSGCenter;

                if (!eventManager)
                {
                    Debug.LogError("There needs to be one active EventManger script on a GameObject in your scene.");
                }
                else
                {
                    eventManager.Init();
                }
            }

            return eventManager;
        }
    }

    public void Init()
    {
        if (eventDictionary == null)
        {
            eventDictionary = new Dictionary<string, Action<ArrayList>>();
        }
    }
    //在需要监听某个事件的脚本中,调用这个方法来监听这个事件
    public static void StartListening(string eventName, Action<ArrayList> action)
    {
        if (instance.eventDictionary.ContainsKey(eventName))
        {
            instance.eventDictionary[eventName]=action;
        }
        else
        {
            instance.eventDictionary.Add(eventName, action);
        }
    }
    //在不需要监听的时候停止监听
    public static void StopListening(string eventName)
    {
        if (instance.eventDictionary.ContainsKey(eventName))
        {
            instance.eventDictionary.Remove(eventName);
        }
    }
    //触发某个事件
    public static void TriggerEvent(string eventName, ArrayList obj)
    {
        if (instance.eventDictionary.ContainsKey(eventName))
        {
            instance.eventDictionary[eventName].Invoke(obj);
        }
    }
}


消息接受类(需注册消息,指定消息的接受方法)

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;

public class EventManagerTest : MonoBehaviour 
{

    void OnEnable()
    {
        Action<ArrayList> action=new Action<ArrayList>(MoveCube);
        MSGCenter.StartListening ("hello", action);
    }

    void OnDisable()
    {
        MSGCenter.StopListening ("hello");
    }

    private void MoveCube(ArrayList obj)
    {
        print("触发了消息"+obj[0]+obj[1]);
    }

}

消息触发类(指定触发的消息)这里传入了一个int型 一个string型

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

public class BtnEventHandle : MonoBehaviour {

    // Use this for initialization
    void Start () {
        
    }

    private void Update()
    {
        if (Input.GetKeyUp(KeyCode.S))
        {
            MSGCenter.TriggerEvent("hello",new ArrayList {1,"str" });
        }
    }
}
 

 

Unity3D中实现自己的消息管理可以使用C#中的委托和事件来实现。具体实现步骤如下: 1. 定义一个消息管理,该包含一个字典,用于存储不同型的消息对应的事件委托。 ``` public class MessageManager { private Dictionary<string, Action> events = new Dictionary<string, Action>(); public void AddListener(string eventName, Action listener) { if (!events.ContainsKey(eventName)) { events.Add(eventName, null); } events[eventName] += listener; } public void RemoveListener(string eventName, Action listener) { if (events.ContainsKey(eventName)) { events[eventName] -= listener; } } public void TriggerEvent(string eventName) { Action action; if (events.TryGetValue(eventName, out action)) { if (action != null) { action.Invoke(); } } } } ``` 2. 在需要订阅消息中,定义一个方法,该方法将被赋值给消息管理器中的委托。 ``` public class Subscriber { private void OnEventTriggered() { // 处理消息 } } ``` 3. 在需要发布消息中,获取消息管理器的实例,然后调用其AddListener方法,将需要订阅消息的方法传入。 ``` public class Publisher { private MessageManager messageManager; private void Start() { messageManager = new MessageManager(); messageManager.AddListener("eventName", OnEventTriggered); } private void OnEventTriggered() { messageManager.TriggerEvent("eventName"); } } ``` 4. 在需要取消订阅消息中,获取消息管理器的实例,然后调用其RemoveListener方法,将需要取消订阅消息的方法传入。 ``` public class Unsubscriber { private MessageManager messageManager; private void Start() { messageManager = new MessageManager(); messageManager.AddListener("eventName", OnEventTriggered); } private void OnDestroy() { messageManager.RemoveListener("eventName", OnEventTriggered); } private void OnEventTriggered() { // 处理消息 } } ``` 通过以上步骤,就可以实现一个简单的消息管理,用于实现订阅/发布模式
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值