Unity3D+SignalR实现实时数据传输

在前面的文章中写过如何搭建SignalR服务端和客户端,也写过如何将Unity3D应用嵌入到WPF中,问题是SignalR服务端和WPF客户端实时通信很简单,SignalR服务端怎么与Unity3D应用实时传输数据呢?下面就开始讨论了。


1.问题背景

1.1为什么要在Unity3D中实时传输数据?

在多人游戏中要实时显示对手的数据,如位置、血量等。在3D业务系统中可能要显示外部提供的一些数据,而这些数据是随时都有可能发生变化的,需要实时在Unity3D应用中显示出来,比如外部采集的温度、湿度等。

1.2为什么要使用SignalR进行实时通信?

选用SignalR进行实时通信并不意味着在Unity3D中进行实时通信只有SignalR这一种方案,只是在之前的文章中使用融合SignalR的WebAPI做服务端已经很顺手了,业务系统也相对成熟,所以打算继续沿用下去。目前常见的方案一般是用Socket做通信,但是需要自己做底层的封装,对于我这种技术菜鸟而言搞不定,所以最终还是希望能够使用SignalR做实时数据传输。

WebAPI集成SignalR

1.3如何将SignalR应用到Unity3D中?

最开始我的想法是,反正都是C#的类库,直接添加进去引用就好了。但是Unity3D编辑器是基于Mono解决方案的,而Mono是基于.Net Framework3.5的,SignalR客户端对运行环境的要求是至少是.Net Framework4.5的,这也就意味着是无法直接在Unity3D中使用SignalR的。问题似乎陷入了僵局,但是天无绝人之类,我们发现在Unity应用商店有一个神奇的插件:BestHttp,对比较常用的网络通信方式进行了封装,包括Http、WebSocket、Socket和我们很熟悉的SignalR。BestHttp比Unity3D自带的www功能丰富很多,但是请注意,BestHttp是收费的,BestHttp是收费的,BestHttp是收费的,重要事情说三遍。

2.解决方案

通过上面的分析,我们决定采用融合SignalR的WebAPI作为客户端,Unity3D融合BestHttp作为客户端,采用之前开发的OPCClient作为采集端,搭建一个实时监测温湿度等环境参数的例子。

融合SignalR的OPCClient实现环境参数实时监测

2.1安装BestHttp

打开Unity3D编辑器,新建项目MonitorDemo,选择菜单Window>Asset Store,打开应用商店查找BestHttp,导入到项目中。

这里写图片描述

导入完成后可以看到Assets目录下面多了一个BestHttp的文件夹,可以在文件夹下找到BestHttp的说明文档,本文中的例子都是基于这份说明文档进行开发的。

2.2搭建Unity3D界面

使用Unity3D的UI添加一个Canvas,添加两个Text,TextTempKey显示“温度”,TextTempValue显示温度数据。
这里写图片描述
为了看的清楚些,加了一个图片做背景。
将Canvas的Render Mode改为Screen Space-Camera,并将Render Camera改为MainCamera,使得Canvas始终以UI界面形式呈现。

2.3创建C#脚本

新建脚本SignalrHelper

public class SignalrHelper : MonoBehaviour
{
    public Text txt;
    private Connection _connection;
    private Hub _proxy;
    readonly Uri _uri=new Uri("http://localhost:49749/MessageBus");

    // Use this for initialization
    void Start () {

        //实例化代理Hub
        _proxy=new Hub("MessageHub");
        //实例化连接
        _connection=new Connection(_uri,_proxy);
        //接收数据事件注册
        _proxy.On("receiveData",ReceiveData);
        //启动连接
        _connection.Open();

    }

    private void ReceiveData(Hub hub, MethodCallMessage methodCall)
    {
        string arg0 = methodCall.Arguments[0].ToString();
        ItemValueModel item = Newtonsoft.Json.JsonConvert.DeserializeObject<ItemValueModel>(arg0);
        Debug.Log("I received data:"+arg0);
        txt.text=item.value;
    }


    // Update is called once per frame
    void Update () {

        }
    }

    void OnDestory()
    {
        if (_connection!=null)
        {
            _connection.Close();
        }
    }
}

其中ItemValueModel是我们定义的监测项数据类

/// <summary>
/// 监测标签数据类
/// </summary>
public class ItemValueModel 
{
    /// <summary>
    /// 标签唯一标识
    /// </summary>
    public string id { get; set; }
    /// <summary>
    /// 标签名称
    /// </summary>
    public string name { get; set; }

    /// <summary>
    /// 标签数据值
    /// </summary>
    public string value { get; set; }
}

将脚本SignalrHelper作为组件添加到Canvas上,并将所定义的Canvas的txt属性设为TextTemp_Value,使得Canvas初始化的时候就能与服务端建立连接,并监听服务端方法receiveData,当接收到数据时将TextTemp_Value的文本改为测点值。

2.4添加服务端方法

public class MessageHub:Hub
{
        public async Task ReceiveData(string data)
        {
            ItemValueModel item = JsonConvert.DeserializeObject<ItemValueModel>(data);
            await Clients.All.receiveData(item);
        }
}

完成以上工作后,启动服务端,然后依次启动采集端(OPCClient)和客户端(Unity3D),看到跳动的数字就说明成功了。

3.方案改进

在上面的步骤已经实现了一个测点的实时数据监测,但显然有点简单了,因为实际上我们在业务系统中不可能只有一个测点,而且并不仅仅只是读取数据,还会有写入数据的情况。另外在上面的示例运行的时候发现测点数据变化频率很快的时候,界面会变得卡顿,于是针对这些问题进行改进。

3.1添加数据处理队列

    private static Queue<ItemValueModel> _queue;

    private void ReceiveData(Hub hub, MethodCallMessage methodCall)
    {
        string arg0 = Newtonsoft.Json.JsonConvert.SerializeObject(methodCall.Arguments[0]);
        ItemValueModel item = Newtonsoft.Json.JsonConvert.DeserializeObject<ItemValueModel>(arg0);
        _queue.Enqueue(item);

    }

接收到测点数据变化时,并不立即处理,而是将数据添加到队列_quene中,在Update方法中去处理数据,这样处理数据就和帧刷新保持一致,避免出现卡顿的现象。

    void Update () {

        if (_queue.Any())
        {
            ItemValueModel item = _queue.Dequeue();
            string tmp = item.id.ToUpper();
            GameObject go = GameObject.FindWithTag(tmp);
            if (go != null)
            {
                Debug.Log(go.name);
                var target = go.GetComponent<Text>();
                if (target != null)
                {
                    target.text = item.value;
                    Debug.Log(target.name + ":" + item.value);
                }
            }

        }
    }

3.2添加数据写入方法

在脚本SignalrHelper中添加写入数据的方法,并通过BestHttp提供的Call方法发送给服务端。

    public Button button;
    public Text text_ID;
    public Text text_Value;
    void Start () {

        //数据处理队列
        _queue=new Queue<ItemValueModel>();
        //按钮事件
        button.onClick.AddListener(delegate()
        {            WriteItem(text_ID.text,text_Value.text);
        });

        //实例化代理Hub
        _proxy=new Hub("MessageHub");
        //实例化连接
        _connection=new Connection(_uri,_proxy);
        //接收数据事件注册
        _proxy.On("receiveData",ReceiveData);
        //启动连接
        _connection.Open();

    }

    private void WriteItem(string id,string value)
    {
        if (_connection!=null&&_proxy!=null)
        {
            _proxy.Call("WriteItem", id, value);
        }
    }

3.3添加界面控件

添加两个Input分别用来输入要写入的标签名称和值,添加一个Button用来发送写入命令,再多加几个Text来表示不同的标签。

这里写图片描述

通过以上的改造我们就能在Unity3D中实现多个测点实时数据的监测和测点数据写入了,也就意味着如果是一个设备监控系统的话,我们就能在Uinity3D里进行设备状态的监测和控制了。


在上面的步骤中,我们使用BestHttp在Unity3D里与SignalR服务端建立连接,实现了实时通信,但仍有部分问题需要解决:
如何将将SignalrHelper作为实时通信的总入口,实现数据传输的模块化?
如何实现测点数据与UI控件的动态绑定?
这些问题也许会在后面的实践中得到解决。

  • 6
    点赞
  • 72
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
Unity3D+DOTS(Data-Oriented Technology Stack)是Unity引擎中的一种新的编程模型和技术堆栈,旨在提供更高性能和更好的可扩展性。DOTS的核心思想是将数据驱动的设计范式应用于游戏开发,以提高游戏的性能和效率。 DOTS包括以下几个主要组件: 1. ECS(Entity Component System):ECS是DOTS的核心部分,它是一种新的编程模型,用于管理游戏对象和组件之间的关系。ECS将游戏对象分解为实体(Entity)、组件(Component)和系统(System),通过数据驱动的方式来处理游戏逻辑。 2. Job System:Job System是Unity3D中的一个并行计算系统,它允许开发者利用多核处理器来执行游戏逻辑。通过将任务划分为小的工作单元(Job),Job System可以实现高效的并行计算,提高游戏的性能。 3. Burst Compiler:Burst Compiler是Unity3D中的一种编译器技术,用于将C#代码转换为高效的机器码。Burst Compiler可以与Job System结合使用,进一步提高游戏的性能。 使用Unity3D+DOTS可以带来以下优势: 1. 更高的性能:DOTS采用数据驱动的设计范式,可以更好地利用硬件资源,提高游戏的性能。 2. 更好的可扩展性:通过ECS和Job System,开发者可以轻松地编写高效的并行代码,并且可以方便地扩展游戏逻辑。 3. 更好的开发效率:DOTS提供了一种简洁而强大的编程模型,可以减少代码量,并且可以更好地组织和管理游戏逻辑。 4. 跨平台支持:Unity3D+DOTS可以在多个平台上运行,包括PC、移动设备和主机等。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值