Filling in with context from your previous question, I understand that you are sending paddle & ball positions from each client to the other. However, as long as the clients agree on where the paddles are at each moment in time, the ball's movement is completely determined (barring rounding errors), and you should experiment zero ball-stutter.
Each client should keep its own internal state with the positions and speeds of paddles and the ball. Pseudocode would be similar to the following:
// 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
This assumes that two package types are being exchanged:
- paddle packets are timestamped positions + speeds of paddles, and are sent whenever a client alters the speed of its own paddle.
- ball packets are timestamped positions + speeds of the ball, and are sent whenever a ball reaches a client's (local) side, whether it bounces off the paddle or not.
The pseudocode is performing extrapolation ("assume things keep on moving as usual") for all unknowns in the update-entities thread. The only point where problems arise is marked with <---
arrows.
You can easily correct for paddle positions by warping them to their new position, possibly interpolating the movement over a short period to make it less jarring.
Correcting for ball positions is easy if both clients more-or-less agree (and then you can do the interpolation trick again, to smoothen it up further). However, one client may see a near miss and another a near hit. In this case, since you are using a peer-to-peer model, we are letting the local client make the call, and explain what happened to the opponent (in another design, you would have a central server making these kinds of decisions; this is good to avoid cheating). You cannot avoid an ugly jump there if both clients disagree - but hopefully, this should be relatively rare and short, unless it coincides with a ping spike.
m_flPredictionErrorTime
). Then you pick up some time over which the smoothing will happencl_smoothtime
. Somewhere close to the display code you calculate how much of error you're going to displayerrorAmount = ( currentTimeMillis() - m_flPredictionErrorTime ) / cl_smoothtime
. Multiply your differences vector over thatvOffset = m_vecPredictionError * errorAmount
and add to the vector of the parameters (x, y, speed, ...). OnceerrorAmount
is greater than 1, you stop considering it (full delta has been displayed) – FederalizeGetPredictionErrorSmoothingVector
function from Valve's Source SDK code. Please share how that worked for you or ask follow up questions – Federalize