在XNA和Lidgren中解决延迟问题

12

我正在尝试在XNA中使用lidgren,但是我遇到了一些“延迟”问题。

我已经下载了他们的XNA示例,发现即使在他们的示例中也存在卡顿问题。情况是,另一侧的移动不够平滑,而我是在局域网上进行尝试的(实际上是在同一台电脑上),而不是通过互联网。

是否有人遇到过由于lidgren和XNA的连接延迟而导致运动不流畅的问题?


4
这个问题似乎不符合主题,需要移动到Gamedev.SE。 - Kromster
1
当这篇文章发布时,gamedevSE在2010年是否活跃? - o0'.
2个回答

38

你提供的示例直接将位置设置为从网络接收到的位置,对于多人游戏来说,这是一个不好的做法!

在真实的游戏中,你应该在本地位置和远程位置之间进行插值。因此,你的接收方法应该看起来像这样:

void Receive(packet)
{
    unit.RemoteX = packet.Read_X_Position();
    unit.RemoteY = packet.Read_Y_Position();
}

这对单位的本地位置没有影响,而是在您的更新方法(每一帧),将本地位置朝远程位置移动:

void Interpolate(deltaTime)
{
    difference = unit.RemoteX - unit.LocalX
    if (Math.Abs(difference) < threshold)
        unit.LocalX = unit.RemoteX
    else
        unit.LocalX += difference * deltaTime * interpolation_constant
}

你需要展示单位的“本地”位置,这样可以实现无延迟的移动:

  1. 如果单位位置几乎到达了远程位置,它将跳到远程位置(然而,它只会跳一个非常小的距离,所以看起来不会有延迟)。
  2. 如果差距太大而无法跳,则缓慢地向应该在的位置移动。

由于单位平稳地移动到应该在的位置,因此看起来就像没有延迟一样!

插值常数控制本地和远程位置收敛的速度:

  • 0:忽略网络更新
  • 小:非常快地跳到位(可能看起来有延迟)
  • 大:慢慢滑入位置,看起来平稳但可能感觉反应迟钝

您需要在这些选项之间选择妥协。

实现这种系统时还有其他要考虑的因素,例如通常希望单位与其远程位置之间有一个上限,否则本地和远程状态可能会在某些情况下变得“卡住”。如果它们相距太远(除了极高的延迟情况外,这种情况不应该发生),您可以停止游戏并告诉用户它太卡了,或者将单位直接跳到位置,这看起来很卡,但游戏至少会继续。

补充说明:重新阅读这个答案,我觉得一个增强方式是跟踪时间差异。如果你知道(大致)系统中的延迟是多少,那么当你接收到包含远程位置的数据包时,你知道那个数据包是从过去的哪个时间点发送过来的。如果你也发送远程速度,你就可以预测对象现在在哪里(假设速度不变)。在某些游戏中,这可能会使估计的本地状态和真实的远程状态之间的差距变小;在其他一些游戏中(其中有许多变化的速度),这可能会使情况更糟。


1
相信我,我本来打算接受这个答案的 :-) 我非常感谢你的邮件合作。 - Andreas Grech
1
@NiCkNewman 当两个事物非常接近时,您可以在不被任何人注意的情况下轻松地捕捉到网络位置。如果您的插值系统足够好,它基本上可以设置为任意低。 - Martin
1
这可能是两种情况之一。要么:1)您需要微调插值常量,要么2)这种方法在根本上受到限制,您需要实现我在附录中添加的内容。基本上,您发送运动向量并预测玩家将如何移动,以便可以更准确地对远程状态进行本地插值。 - Martin
2
我不同意“使用常数1会直接传送到网络位置”的说法。 - Dmytro
1
在我的算法实现中,移动会产生一些摩擦力,在大多数游戏中这很好,但并非总是如此。我认为这是因为每个更新循环中的线性插值,导致差异减小,从而整体变得非线性(我希望我的意思很清楚)。 - user11909477
显示剩余8条评论

1

我一直在考虑编写一个多人游戏,从仅移动一些立方体并在另一台机器上复制位置/旋转的演示开始,该机器处于观察模式。

我正在使用您上面的代码示例,它运行良好(我不得不将插值常数调高到1以上才能使其看起来平滑)。

我看过一些插值示例,这些示例考虑了当前时间和接收到的消息时间戳之间的时间差。

我发现此代码没有使用时间差,因此插值需要尽可能长的时间才能达到目标值(或者至少在阈值范围内才能捕捉到位置)。我的问题是,这样做有什么优势吗?

非常感谢。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接