这是一个老问题,但我最近编写了类似的代码,所以也许这会对某人有所帮助。
是的,延迟在计算中总是有用的。但它比 RTT 稍微复杂一些。往返时间总是在变化......您的网络代码可以保持平均值,但与该平均值的差异很大。
本地客户端、远程客户端和服务器都使用算法预测当前位置。以下数据接近典型值:
- 时间:吨
- 放置:位置 (x,y,z) 和方向 (x,y,z,w)
- 运动:直线运动矢量以长度为速度(x,y,z),旋转运动矢量以长度为轴(x,y,z)
您需要从 [T,P,M] 集合推断为 simtime 的算法。我不会在这里提供这些。
当客户端在 [T,P,M] 处注册船舶驱动器的更改时,直到 T+deltaT 才会到达服务器。但如果 deltaT 在典型网络延迟的容差范围内,服务器可以说“是的,它发生在 T,我接受”。否则它可能想要纠正客户端说“不,这超出了容忍度,它发生在我的时间 T'”在这种情况下,客户端将不得不重播所有随后驱动的 [T,P,M] 从服务器更正的更改(这意味着您需要保留一个队列或它们的列表)。
下一个客户将在 T+deltaT+differentdeltaT 获得它。它不可能改变它已经模拟的东西,所以如果它没有延迟它的模拟,它会跳过远程船,你会看到一个混蛋帧。这就是为什么远程驱动的船舶应该将其模拟延迟始终大于 2*typicaldeltaT 的时间。它应该是一个持续的延迟,或者是一个逐渐变化的延迟,在严重滞后的时候,你仍然会看到 jerk 帧
你可以用额外的平滑代码来平滑所有的混蛋,但在你的代码完美无瑕之前不要这样做,因为它只会让人无法看到问题出在哪里。
您必须有一个良好的同步时间参考。那里的许多代码做得相当草率(例如,RakNet 没有(或没有)做得很好)。这里有一个很好的提示:短期内你可以假设每个人的时钟都在以相同的速率运行,你只需要弄清楚偏移量是多少,所以保持一个最大和最小偏移量的窗口,并在你学习时关闭它;从长远来看,您需要补偿时钟运行速度快或慢的客户,因此如果您确定必须打开窗口,请允许它打开。您必须使用单调递增的本地时间源,并且不会影响处理器速度(现在是可变的)。
不,不要在本地“化身”移动时延迟本地模拟。这似乎太没有反应了。您可以稍微延迟它(最多可能 50 毫秒)以帮助改善同步,但是一直延迟到 RTT 会使您的游戏看起来令人沮丧地没有响应。设置本地延迟选项并使用它,因为可以接受小的一致延迟并改善同步。但这不是必需的,并且会导致很多问题,因此我建议最后执行该代码。(如果您正在尝试制作 FPS 近战游戏,则需要执行此操作以及您可以获得的所有其他帮助)。
至于作弊预防与模拟平滑度:首先,当官方位置发生变化时,客户不应仅从最后已知位置推断。它应该注册一个调整向量并缓慢地从旧路径移动到新路径以获得平滑度(但就像我上面所说的那样,最后执行此代码,否则它将掩盖其他错误)。其次,服务器应该容忍大范围的延迟......即使在同一以太网上的机器上,数据包延迟通常运行 5ms 到 100ms 左右......这是一个相当大的范围。当然,你需要打断它并说“如果你说你在 T 时间搬家,但我在 T + some_large_number 收到了数据包,那么我认为你是在试图调整过去并对我撒谎。” some_large_number 不应该比平均 RTT 大很多,以保持人们诚实。
模拟永远不会紧密同步。它们应该在 Internet 上保持在 400 毫秒左右,但在延迟时间肯定会超出这个范围……到 30 秒或更长时间,你需要容忍这种情况,因为它们并不罕见。鉴于 Internet 受到铜缆中光速的限制,您始终可以预期,对于您的远方客户端,单向延迟通常在至少 100 毫秒的范围内,通常为 500 毫秒或更长。
所以我强烈建议你不要尝试在互联网上制作近战FPS游戏(一些大公司尝试但总是会遇到麻烦)。如果您使用射弹(通过在一个模拟中快速运行它们而在另一个模拟中慢速运行),您可以做一些技巧,这样即使时间关闭,它也会继续显示。此外,FPS游戏使用的规则是命中检测是基于攻击者的模拟......当攻击者知道他已经死在目标上并没有击中时,感觉更错误,然后当防守者知道他不在路上并被击中时感觉更错误无论如何。你必须选择一个或另一个,从心理上来说就是这样。近战需要一定程度的同步,坦率地说这是不可能的,大多数游戏公司不会接触 MMORPG FPS 近战,而是使用自动瞄准(尝试玩 Mortal Online,
祝你好运。