你提供的示例直接将位置设置为从网络接收到的位置,对于多人游戏来说,这是一个不好的做法!
在真实的游戏中,你应该在本地位置和远程位置之间进行插值。因此,你的接收方法应该看起来像这样:
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以上才能使其看起来平滑)。
我看过一些插值示例,这些示例考虑了当前时间和接收到的消息时间戳之间的时间差。
我发现此代码没有使用时间差,因此插值需要尽可能长的时间才能达到目标值(或者至少在阈值范围内才能捕捉到位置)。我的问题是,这样做有什么优势吗?
非常感谢。