Hello. I’m creating a 1v1 game with an authoritative server and two clients.
My whole network is based on UDP packets:
- sending positions from clients
- sending confirmations them from the server (and deleting old ones on client)
- sending ‘non cheated’ positions to the opponent from the server
Everything was okay, until the last issue appeared.
When I send positions from the server to the opponent, they are being received in different timings. An example:
-
- Position 1 comes in 43 ms
-
- Position 2 comes in 15 ms (from the previous one)
-
- Position 3 comes in 34 ms
-
- Position 4 comes in 10 ms
-
- Position 5 comes in 35 ms
As we all know - THIS IS NETWORKING, it is impossible to make it ‘stable’ that every packet comes within a constant: 30 ms time (omg that would be perfect).
And here comes my problem, I don’t know how to adjust the interpolation that the ‘opponent’ is drawn as smooth as a normal player (me on my phone).
When the process is static (I click arrows and move my player ‘step by step’) it is really, really smooth. My gameloop has some timings and it works really well.
But when I receive my opponent’s position and set his ‘desiredPosition(x,y)’ his movement is not smooth, his ‘positions’ are not ‘updating’ in a constant time but with random delays (cause we get these positions in different timings).
And example of my issue:
The gameloop:
@Override
public void run(){
long beginTime; // the time when the cycle begun
long timeDiff; // the time it took for the cycle to execute
int sleepTime; // ms to sleep (<0 if we're behind)
int framesSkipped; // number of frames being skipped
while(match_running){
beginTime = System.currentTimeMillis();
framesSkipped = 0; // resetting the frames skipped
// update game state
// MOST IMPORTANT METHODS - look below
player_me.updatePosition(); // move me (smoothly) to desired position
player_op.updatePosition(); // move the opponent (smoothly)
// render state to the screen
// draws the canvas on the panel
repaint();
// calculate how long did the cycle take
timeDiff = System.currentTimeMillis() - beginTime;
// calculate sleep time
sleepTime = (int)(FRAME_PERIOD - timeDiff);
if (sleepTime > 0) {
// if sleepTime > 0 we're OK
try {
// send the thread to sleep for a short period
// very useful for battery saving
Thread.sleep(sleepTime);
} catch (InterruptedException e) {}
}
while (sleepTime < 0 && framesSkipped < MAX_FRAME_SKIPS) {
// we need to catch up
// update without rendering
player_me.updatePosition(); // move me to desired position
player_op.updatePosition(); // move the opponent
// add frame period to check if in next frame
sleepTime += FRAME_PERIOD;
framesSkipped++;
}
// sending positions every 30 seconds
time_now = System.currentTimeMillis();
if(time_now >= (packet_past_time + 30)) {
sendPositions();
packet_past_time = System.currentTimeMillis();
}
}
}
Listening for ‘opponent’s positions’:
public void received(Object o){
if(object instanceof OpponentPositionList)
player_op.setDesiredPosition(object.x, object.y);
}
So we set his new ‘desired position’. The Gameloop is always calling his ‘updatePosition()’ which should move him to the ‘desired position’. And it works totally smoothly with ‘Player Me’ cause it updates positions constantly, but it freezes when receiving positions ‘not constantly’ from the opponent:
public void updatePosition(){
double xDistance = desiredX - this.x;
double yDistance = desiredY - this.y;
double distance = Math.sqrt(xDistance * xDistance + yDistance * yDistance);
if (distance > 1) {
this.x += xDistance * 0.5;
this.y += yDistance * 0.5;
}else{
this.x = Math.round(this.desiredX);
this.y = Math.round(this.desiredY);
}
}
The main question is:
If positions come not ‘constantly’, with random 10-50 ms delays how to draw the opponent as smooth as a normal player on this device? With some sort of ‘timed interpolation’ or something?
Any suggestions would be awesome. Thanks!