将"橡皮筋"解决多人插值口吃?

时间:2016-10-11 12:07:53

标签: java networking interpolation physics multiplayer

我用UDP编写了多人Pong。我正在使用插值和外推法,以便在客户端上创建平滑的效果。

有效。然而,球中有一些不断的口吃。每次收到新数据包时它会向前跳一小部分。它看起来有些迟钝,但它是可玩的。

必须有办法让游戏看起来更顺畅。我读过有关橡皮筋的文章。离开这里最好的方法是什么?

我希望能够很好地回答我的问题的人会找到它。

更新

根据Ivan的要求,这是ping时间的图表。但是,我确实认为客户端平滑代码中存在问题。

enter image description here

2 个答案:

答案 0 :(得分:6)

previous question填写上下文,我知道您正在发送paddle&从每个客户到另一个客户的球位置。但是,只要客户同意每个时刻桨的位置,球的运动就完全确定了(除了四舍五入的错误)​​,你应该尝试零球的口吃。 每个客户应该保持自己的内部状态与桨和球的位置和速度。伪代码类似于以下内容:

<---

这假设正在交换两种包类型:

  • paddle数据包是带时间戳的位置+ paddle的速度,只要客户改变自己的paddle速度就会发送。
  • 球包是带时间戳的位置+球的速度,并且每当球到达客户端(本地)时发送,无论它是否从球拍反弹。

对于更新实体线程中的所有未知数,伪代码正在执行外推(&#34;假设事情继续照常移动&#34;)。出现问题的唯一方面是标有$len箭头。

您可以通过将它们翘曲到新的位置来轻松校正桨位置,可能会在短时间内插入运动以减少它的震动。

如果两个客户或多或少都同意,那么校正球位置很容易(然后你可以再次进行插值技巧,以进一步平滑它)。但是,一个客户可能会看到近乎未命中,另一个客户可能会看到接近命在这种情况下,由于您使用的是点对点模型,我们让本地客户端进行呼叫,并解释对手发生了什么(在另一种设计中,您将有一个中央服务器做出这些决定;这样可以避免作弊)。如果两个客户都不同意,你就不能避免那种丑陋的跳跃 - 但希望这应该是相对罕见和短暂的,除非它与ping峰值一致。

答案 1 :(得分:2)

允许摆脱此效果的一个想法是在客户端上应用错误预测更正时使用平滑

如何运作

在您的代码中的某个时刻,您确定球位置和客户端是不同的。

Discrepancy

不是立即将其应用于客户端代码的修正(这是您可以看到这些跳转的一个原因),而是在一段时间内执行该操作,cl_smoothtime 500毫秒。

首先,您的程序应该存储错误检测事件发生的时间m_flPredictionErrorTime

public void onErrorDetected() {
    this.m_flPredictionErrorTime = System.currentTimeMillis();
}

在接近显示代码的某处,您可以计算出要显示的错误量。这是一些伪代码。

public void draw() {
    Point preditctionError = this.clientPredictedBallCoordinates - this.serverCoordinates;
    Point deltaToDisplay = calculateErrorVector(preditctionError);
    Point positionToDisplay = clientPredictedBallCoordinates + deltaToDisplay;
    // actually draw the ball here
}

public Point calculateErrorVector(Point coordinatesDelta) {
     double errorAmount = ( System.currentTimeMillis() - this.m_flPredictionErrorTime ) / this.cl_smoothtime.
     if (errorAmount > 1.0) {
         // whole difference applied in full, so returning zero delta
         return new Point(0,0);
     }
     if (errorAmount < 0) {
         // no errors detected yet so return zero delta
         return new Point(0,0);
     }
     Point delta = new Point(coordinates.x*errorAmount, coordinates.y*errorAmount);
     return delta;
}

我从Source Multiplayer Networking wiki中选择了这个想法。 Cpp中的实际代码示例可在其GetPredictionErrorSmoothingVector function的SDK中找到。