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

时间:2017-03-05 16:27:02

标签: c# multiplayer game-development

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

基本上,我有playerObject将其位置数据(Vector3(x,y,z))作为JSON字符串发送到服务器,服务器将其发送回所有其他播放器。 / p>

事物的插座方面正在顺利进行。从创建数据包到收到数据包的延迟非常小。

但是当我们尝试取消JSON远程客户端的位置时,我在我的客户端上发生了大量延迟:

Vector3 remotePos = JsonUtility.FromJson<Vector3>(_command.Substring(5 + _usernameLength));

Json字符串在字符串的开头有一个标识符,表示它是一个Position更新,后跟两个表示用户名长度的数字,然后是用户名(以便远程客户端可以更新正确的{{1整个字符串看起来像这样。

playerObject

从服务器收到此类数据包后,我的客户将执行以下任务:

POS09NewPlayer{"x":140.47999572753907,"y":0.25,"z":140.7100067138672}

所有这些“都有效”,但只有3个客户同时连接后才会变得非常缓慢。

我做错了什么?必须有一个重大缺陷,因为我只为每个.015秒发送3个玩家的更新,其中像战地这样的游戏可以为64个玩家每秒发送60个更新!

任何建议都将受到赞赏。

1 个答案:

答案 0 :(得分:6)

嗯,肯定有优化的空间。由于您引用大型游戏引擎作为参考,我将根据较旧的虚幻引擎版本和他们正在使用的一些优化给您一些示例:

  • 网络包使用UDP协议。它仍然需要自己处理丢弃的,重复的或无序的包,但它吞下了那个苦涩的药丸,而不是使用实际的TCP连接,因为后者会引入更多的开销。
  • 服务器会跟踪它发送给客户端的更新信息。对于服务器复制的客户端上的每个对象,服务器会跟踪所有变量。在每次游戏循环更新结束时,服务器将检查哪些变量实际上具有与服务器上次向客户端发送更新时不同的值。并且只有在实际存在差异时,才会将新值发送给客户端。这似乎是一个令人难以置信的开销,但网络带宽是一个比系统内存和CPU时间更少的资源。
  • 在通过网络发送之前,实际上会截断矢量信息。引擎使用float作为其向量组件的数据类型,但它仍然将X,Y和Z舍入到最接近的整数并传输它们而不是完整的浮点数据。这样它们只占用几个字节到几个字节,而不是12个字节的未压缩原始浮点数。
  • 在客户端模拟位置更新,并与来自服务器的传入数据合并。为避免从位置更新中抖动,客户端根据其速度值预测对象的新位置。当客户端稍后从服务器接收到位置更新时,它将优雅地将对象稍微移动到新位置(基本上是客户端和服务器坐标之间的折衷),并且如果服务器的位置与服务器的位置相差太大,则仅进行硬更新。客户的版本。这是通过很多方面完成的。如果玩家射击射弹,则在服务器上执行该射击,这将创建射弹并将其发送给玩家以更新其位置。但是玩家还将接收关于镜头的函数调用并在本地创建射弹并更新其轨迹。即使那个射弹实际上不能杀死客户端的玩家,它的轨迹和效果仍然可以在本地模拟,给人以流畅的游戏玩法的印象。如果它碰到某些东西,可以在该位置播放适当的效果,而不需要服务器告诉客户端创建这些效果。
  • 服务器会跟踪每个玩家的相关内容。如果玩家位于地图的另一侧,在几面墙后面,则无需向您发送有关该玩家行为的任何更新。如果该玩家的抛射物后来恰好进入您的视野,服务器仍然可以在适当的时间告诉您这些射弹。

整件事情要比我在这篇文章中所能解决的问题复杂得多,但其主要内容可能是:网络带宽是多人游戏中最有限的资源,因此引擎不受限制地发送尽可能少的信息包,因为它可以逃脱。

注意什么?对于此引擎中的整个向量,位置向量的不到一个组件已经被认为太大了。我想JSON确实在这里引入了一些开销,仅仅是因为它的冗长。当你也可以发送它们的实际位并从实际包中推断它们的含义时,你将数字作为字符串发送。