// input thread
if input changed,
alter paddle speed and/or direction
send timestamped message to inform my opponent of paddle change
// incoming network thread
if paddle packet received
alter opponent's paddle speed and/or direction at time it was sent
fix any errors in previously extrapolated paddle position <--- Easy
if ball-packet received
fix any errors in ball position and speed <--- Tricky
// update entities thread
for each entity (my paddle, opponent paddle, the ball)
compute updated entity position, adjusted by time-since-last-update
if ball reached my end, send ball-packet to other side
draw updated entity
假设两种数据包正在交换:
伪代码对于update-entities线程中所有未知量执行外推(“假设事物按照惯常方式继续移动”)。唯一出现问题的点用<---
箭头标记。
您可以通过将挡板位置扭曲到新位置来轻松纠正挡板位置,并可能在短时间内插值移动以使其更加平滑。
如果两个客户端都大致同意,则很容易纠正球位置(然后您可以再次使用插值技巧,以进一步平滑它)。但是,一个客户端可能会看到近似错过,而另一个客户端可能会看到近似命中。在这种情况下,由于您正在使用点对点模型,我们让本地客户端进行调用,并向对手解释发生了什么(在另一种设计中,您将有一个中央服务器做出这些决策;这是避免作弊的好方法)。如果两个客户端不同意,您无法避免出现一个丑陋的跳跃-但是希望这种情况相对较少且短暂,除非它与ping峰值重合。
将其立即应用于客户端代码作为更正措施(这也是您可以看到这些跳跃的原因之一)的做法改为在一段时间内执行,例如500毫秒的cl_smoothtime
。
首先,您的程序应该存储错误检测事件发生时的时间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;
}
m_flPredictionErrorTime
)。然后,您需要选择一些时间来进行平滑处理cl_smoothtime
。在接近显示代码的某个地方,您需要计算要显示的错误量errorAmount = (currentTimeMillis() - m_flPredictionErrorTime) / cl_smoothtime
。将您的差异向量乘以该值vOffset = m_vecPredictionError * errorAmount
,并添加到参数向量(x、y、速度等)中。一旦errorAmount
大于1,您就可以停止考虑它(完整的增量已经被显示)。 - Ivan