C# 在多人游戏中,如何通过套接字高效地发送位置数据?

C# 在多人游戏中,如何通过套接字高效地发送位置数据?,c#,multiplayer,game-development,C#,Multiplayer,Game Development,我目前正在为Unity游戏构建自己的网络代码(用于学习体验),在“解码数据包”方面遇到了一些严重的延迟 基本上,我有playerObject,它将位置数据(Vector3(x,y,z))作为JSON字符串发送到服务器,服务器将其发送回所有其他玩家 事情的插座端进展顺利。从创建数据包到接收数据包的延迟很小 但是,当我的客户端尝试取消远程客户端的JSON位置时,我的客户端受到了巨大的延迟: vector3remotepos=JsonUtility.FromJson(_command.Substrin

我目前正在为Unity游戏构建自己的网络代码(用于学习体验),在“解码数据包”方面遇到了一些严重的延迟

基本上,我有
playerObject
,它将位置数据(Vector3(x,y,z))作为JSON字符串发送到服务器,服务器将其发送回所有其他玩家

事情的插座端进展顺利。从创建数据包到接收数据包的延迟很小

但是,当我的客户端尝试取消远程客户端的JSON位置时,我的客户端受到了巨大的延迟:

vector3remotepos=JsonUtility.FromJson(_command.Substring(5+_usernameLength))

Json字符串在字符串的开头有一个标识符,表示它是一个位置更新,后面是两个数字,表示用户名的长度,然后是用户名(这样远程客户端就可以更新适当的
playerObject
。整个字符串看起来像这样

POS09NewPlayer{“x”:140.47999572753907,“y”:0.25,“z”:140.7100067138672}

从服务器接收到这样的数据包后,我的客户端将执行以下任务:

        int _usernameLength = Int32.Parse(_command.Substring(3, 2));
        string _username = _command.Substring(5, _usernameLength);
        Vector3 remotePos = JsonUtility.FromJson<Vector3>
        if (_username != username)
        {
        playerDict[_username].transform.position = remotePos;
        } 
int\u usernameLength=Int32.Parse(_command.Substring(3,2));
字符串_username=_command.Substring(5,_usernameLength);
Vector3 remotePos=JsonUtility.FromJson
如果(_username!=用户名)
{
playerDict[\u用户名].transform.position=remotePos;
} 
所有这些都“起作用”,但在3个客户端同时连接后,速度会变得非常缓慢

我做错了什么?肯定有一个明显的缺陷,因为我只为3名玩家每0.015秒发送一次更新,而像《战场》这样的游戏可以为64名玩家每秒发送60次更新


任何建议都将不胜感激。

好吧,当然还有优化的空间。由于您引用的是大型游戏引擎作为参考,我将根据较旧的虚幻引擎版本和它们正在使用的一些优化为您提供一些示例:

  • 网络包使用UDP协议。它仍然需要自己处理掉的、重复的或无序的包,但它吞下了这个苦果,而不是使用实际的TCP连接,因为后者会带来更多的开销
  • 服务器跟踪它发送给客户端的信息更新。对于服务器复制的客户端上的每个对象,服务器跟踪所有变量。在每次游戏循环更新结束时,服务器将检查哪些变量的值与服务器上次向客户端发送更新时的值不同客户端。只有在实际存在差异的情况下,才会将新值发送给客户端。这似乎是一种难以置信的开销,但网络带宽比系统内存和CPU时间少得多
  • 向量信息在通过网络发送之前实际上会被截断。引擎使用float作为其向量组件的数据类型,但它仍然将X、Y和Z舍入到最接近的整数,并传输这些整数,而不是完整的浮点数据。这样,它们只占用几位到几个字节,而不是unco的12个字节压缩原始浮动
  • 位置更新在客户端模拟,并与来自服务器的传入数据合并。为了避免位置更新带来的抖动,客户端根据对象的速度值预测对象的新位置。当客户端稍后从服务器接收到位置更新时,它将优雅地将对象稍微移动到新位置n(基本上是客户端和服务器坐标之间的折衷)只有当服务器的位置与客户端的版本相差太大时,才进行硬更新。这需要做很多事情。如果玩家射击射弹,该射击将在服务器上执行,服务器将创建射弹并将其发送给玩家以更新其位置。但玩家还将收到有关sho的函数调用t并在本地创建投射物并更新其轨迹。即使该投射物实际上无法杀死客户端的玩家,其轨迹和效果仍然可以在本地模拟,以给人一种流畅的游戏体验。如果它击中了什么东西,可以在不需要服务器告知的情况下在该位置播放适当的效果客户端创建这些效果
  • 服务器跟踪与每个玩家相关的内容。如果某个玩家在地图的另一边,在几堵墙后,它不需要向您发送有关该玩家行为的任何更新。如果该玩家的投射物稍后碰巧出现在您的视图中,服务器仍然可以在适当的时间告诉您有关这些投射物的信息e
整个问题比我在这篇文章中所能说的要复杂得多,但其要点可能是:网络带宽是多人游戏中最有限的资源,因此引擎会尽可能少地发送信息包


注意到了吗?对于这个引擎中的整个向量来说,少于一个位置向量的分量已经被认为太大了。我想JSON确实引入了一些开销,这仅仅是因为它的冗长性。当您也可以发送数字的实际位并推断其含义时,您将数字作为字符串发送从实际的包中。

至少移动
JsonUtility.FromJson
中的
if
我非常怀疑json反序列化会在这方面造成如此巨大的影响case@Evk我在计算json数据包的同时计算收到的数据包。我接收数据包的速度大约是我能够使用json的三倍。这意味着数据包远远落后于json。W哦,谢谢你的评论…有很多有用的信息。你能详细介绍一下吗