unity 反射实现简易广播系统(脚本通信)

unity自带消息通信功能SendMessage效率比较低(当场景中的对象和脚本组件比较多的时候),在帧里面调用更是灾难的.

试了c#的各种delegate, invoke,效果不好.

最终通过C#反射的方式写了一个订阅广播消息系统.下面讲解一下原理

1.反射:

看这里 https://www.cnblogs.com/Stephenchao/p/4481995.html

2.观察者模式:

 看这里 https://www.cnblogs.com/zhili/p/ObserverPattern.html

运行流程

1.通过反射的方式获取到对象的MethodInfo

2.将对象和MethodInfo封装成observer整洁点,打包到list中,再放到一个Dictionary中备用

3.发送消息的时候从Dictionary获取到observer列表,反射调用即可,相信Dictionary的查询效率应该很高微笑

在几个小项目里面试了一下,效果还不错,对于不怎么使用puremvc和ECS,喜欢简单的同学来说还是比较适合的,直接上代码吧

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

public class MiniBroadCast {

    public static MiniBroadCast Instance = new MiniBroadCast();

    private Dictionary<string, List<Observer>> m_method_info = new Dictionary<string, List<Observer>>();

    /**
     * 注册观察者
     */
    public void registListener(string key,string method_name,object instance)
    {
        if (!m_method_info.ContainsKey(key))
        {
            m_method_info[key] = new List<Observer>();
        }
        MethodInfo method = instance.GetType().GetMethod(method_name, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
        Observer _observer = new Observer();
        _observer.method = method;
        _observer.instance = instance;
        m_method_info[key].Add(_observer);
        //Debug.Log("regist observer success: instance:" + instance + " method:" + method);
    }

    /**
 * 注册观察者
     * 静态
 */
    public void registListener(string key, string method_name, Type type)
    {
        if (!m_method_info.ContainsKey(key))
        {
            m_method_info[key] = new List<Observer>();
        }
        MethodInfo method = type.GetMethod(method_name, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static);
        Observer _observer = new Observer();
        _observer.method = method;
        _observer.instance = null;
        m_method_info[key].Add(_observer);
    }
    /**
     * p_params:不定参数
     */
    public void breadcast(string key,params object[] p_params)
    {
        //Debug.Log(key);
        if (!this.m_method_info.ContainsKey(key))
        {
            Debug.LogWarning("observer not find");
            return;
        }
        //反射调用(包括静态方法)
        List<Observer> _list = new List<Observer>();
         //深度复制一份,避免在反射执行过程中删除观察者出现错误
        foreach (Observer o in this.m_method_info[key]){
            _list.Add(o);
        }

        foreach (Observer o in _list)
        {
            o.method.Invoke(o.instance, p_params);
        }
    }

    public void removeListener(string key, string method_name, object instance)
    {
        if (!m_method_info.ContainsKey(key))
            return;

        List<Observer> _list= this.m_method_info[key];
        for (int i = _list.Count-1; i>=0; i--)
        {
            if (_list[i].instance == instance && _list[i].method.Name == method_name)
            {
                _list.RemoveAt(i);
                Debug.Log("observer remove success!");
            }
        }

        if (_list.Count == 0)
            this.m_method_info.Remove(key);

    }

    public void cleanAll()
    {
        m_method_info = new Dictionary<string, List<Observer>>();
    }
    private class Observer
    {
        public object instance;
        public MethodInfo method;
    }
}

使用方法很简单

1.直接放到项目下面

2.MiniBroadCast.Instance.registListener订阅消息

3. MiniBroadCast.Instance.breadcast广播消息

4. MiniBroadCast.Instance.removeListener取消订阅

5. MiniBroadCast.Instance.cleanAll清除所有订阅

github地址:

https://github.com/baixin1228/unity-breadcast-framwork

后续还会放出Attribute版本的,用法上面更加简易,不需要主动订阅

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值