MudbuG
Member
I would like feedback on the following code that I am using in the step event of a network object that implements (or attempts to implement) snapshot interpolation.
While the results are much better than just raw position updates, there is still some jitter. I am not sure if the jitter can be completely eliminated, or if I have to live with it.
Some things to note:
While the results are much better than just raw position updates, there is still some jitter. I am not sure if the jitter can be completely eliminated, or if I have to live with it.
Some things to note:
- time_offset was arrived at by a clock sync message to the given peer. I sent current_time to the peer, received the peers current_time, calculated round trip and offset from reply.
- the object being interpolated is a remote tank. Tank movement is time-based vector movement with smooth acceleration and deceleration (which probably complicates the jitter issue)
- I get about a 200 MS RTT with GameSparks (100ms lag), and I am targeting between 120ms to 150ms delay for the interpolation.
Code:
/// @description Interpolate Movement
// must have at least 2 states in history in order to interpolate
if (ds_list_size(interp_buffer) < 2) return;
// determine target render time
var renderTime = current_time - (interp_back + time_offset); //time we want to show the position for (adjusted to remote time clock)
// find most recent state whose time that is <= our target renderTime
var index = ds_list_size(interp_buffer) - 1; //start at the end, it has most recent state, and iterate backward
while (true)
{
var item = interp_buffer[|index];
var itemTime = item[?"time"];
if (itemTime <= renderTime)
{
break;
}
index--;
if (index < 0)
{
//reached end of list, can't interpolate, exit the script
exit;
}
}
// make sure we have 2 states
if (index >= ds_list_size(interp_buffer) - 1)
{
// can't interpolate... not enough states.
// optional: could just set to this position, or try to extrapolate
exit;
}
//
// Interpolate between the 2 positions we found
//
var p1 = interp_buffer[|index-1]; //target renderTime or older
var p2 = interp_buffer[|index]; //newer than target renderTime
var p1Time = p1[?"time"];
var p2Time = p2[?"time"];
var x1 = p1[?"x"]; var x2 = p2[?"x"];
var y1 = p1[?"y"]; var y2 = p2[?"y"];
var velocity_x1 = p1[?"velocity_x"];
var velocity_x2 = p2[?"velocity_x"];
var velocity_y1 = p1[?"velocity_y"];
var velocity_y2 = p2[?"velocity_y"];
var totalTime = p2Time - p1Time;
var pos = (renderTime - p1Time)/totalTime; //find position between 0 and 1 so we can use lerp
// set actual lerped position (x and y) and angles
if (abs(x1-x2) > 1) x = lerp(x1, x2, pos);
if (abs(y1-y2) > 1) y = lerp(y1, y2, pos);
//velocity is only used to set image_angle for now.
velocity_x = lerp(velocity_x1, velocity_x2, pos);
velocity_y = lerp(velocity_y1, velocity_y2, pos);
image_angle = point_direction(0, 0, velocity_x, velocity_y) - 90; //-90 used becuase sprite is not oriented properly
// directly set turret angle without interpolation
turret.image_angle = p2[?"turret_angle"];