Skip to content

Instantly share code, notes, and snippets.

@timetocode
Created April 23, 2014 22:43
Show Gist options
  • Save timetocode/11235041 to your computer and use it in GitHub Desktop.
Save timetocode/11235041 to your computer and use it in GitHub Desktop.
Entity interpolation
/* Entity Interpolation
this code occurs within the draw loop for an entity
this.x and this.y represent the most recently received server position of
the entity -- though i don't ever intend to use it for drawing
when an update is received (roughly every 50ms in my particular game) this.x and this.y get
pushed into previousState.x and previousState.y
i also continue sloppily onwards to previousPreviousState.x, but I've removed that code
the goal is to have a renderTime which is at least one tick in the past (e.g. if
ticks are 50ms apart, a render time between 50-100ms in the past), and then interpolate between two
already-known position for an entity (.: all entities are drawn slighly in the past, relative
to information we have about them)
pseudo code:
e.g. received tick:260 x:5, y:5, at clientTimestamp: 1000; (known position A)
and then tick:261, x:6, y:5 at clientTimestamp: 1052; (known position B)
now let's say the client is rendering at 60 fps (irrelevant) and we're following the
logic for a hypothetical draw call
current client time: 1096 (hypothetical)
renderTime: 1046 (1096 - 50)
how far from known position A 1000 to known position B 1052 is 1046? (46/52ths of one tick, aka 0.88)
lerp 88% of the way from from position A to position B
done! draw the entity 0.88 of the way between A and B for this particular frame
nextframe:
current client time 1112
renderTime: 1062 (hopefulyl we've received another known position by now, b/c this comes after postion B)
etc!
*/
// actual code
var past = 1000/tickRate
var now = Date.now()
var renderTime = now - past // the exact time (in the past) for which we will create a position, in this case this is ~1 tick ago
// timestamp of a previous position (presumably one tick older than t2)
var t1 = previousState.lastUpdate
// timestamp of most recent position update form server
var t2 = this.lastUpdate
// if we have positional data within this time range
if(entityInterpolationEnabled && renderTime <= t2 && renderTime >= t1) {
// total time from t1 to t2
var total = t2 - t1
// how far between t1 and t2 this entity is as of 'renderTime'
var portion = renderTime - t1
// fractional distance between t1 and t2
var ratio = portion / total
var interpX = math.lerp(previousState.x, this.x, ratio)
var interpY = math.lerp(previousState.y, this.y, ratio)
// draw this entity at the interpolated position
this.drawEntity(interpX, interpY)
} else {
// no interpolation at all, just draw the raw position
this.drawEntity(this.x, this.y)
// in the actual code I attempt some extrapolation when draw is called in a range outside of t1 to t2
// this usually only occurs if the connection or server lag, and renderTime falls into a window for which we have yet
// to receive any data
// tuning the variable 'past' can minimize
}
@gustavgenberg
Copy link

Oh My Goddd!!! This is EXACTLY what i wanted 💃

@simon-kyger
Copy link

Thank you! This is the guy from youtube who commented ;)

@suprafun
Copy link

suprafun commented Feb 7, 2018

Thank-you so very much for this code sample, if I may ask under what license is this snippet released under ? Thank-you.

@czarecoo
Copy link

czarecoo commented Jan 5, 2019

still helpful, thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment