• 10
• 9
• 13
• 10
• 18

How do I "tween" between rendering when using fixed-rate timesteps? (2D)

This topic is 4066 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

Recommended Posts

I'm going to use fixed-timestep logic for my 2D game but I'm confused on how to implement render-tweening. According to the articles on gaffer.org, it is easy to use linear interpolation based on the amount left in the accumulator. (since my game is 2D) So, for example... Let's say I have a ball moving in a circle at a rate of 4 seconds per full rotation. After 2 seconds the ball is halfway around the circle. My accumulator (eg. the amount left over after performing full timestep updates) says that we are 1/10th (0.1) of the way to the next timestep. Where should I draw my ball? I can't perform an update on the ball because that would ruin my fixed-rate logic. Do I somehow move the ball in a straight line? If so, how do I know where to move it? Thanks for your help...

Share on other sites
No don't use a straight line, this is the kind of thing that trigonometric functions are perfect for. sin(Theta) gives you your Y value at a rotation of Theta (in radians) along a unit circle so if you can calculate your radians per second of the circle (1/4) than all you have to do is interpolate the radians by that much

Draw the circle at (Radius * cos(Theta + (1/4 * Seconds * 2pi)), Radius * sin(Theta + (1/4 * Seconds * 2pi)))

Your X and Y values respectively

I'm pretty sure thats right but It's late and I'm headed to bed, you can find a ton more in depth explanation of trigonometric functions on google.com

Share on other sites
Quote:
 My accumulator (eg. the amount left over after performing full timestep updates) says that we are 1/10th (0.1) of the way to the next timestep.Where should I draw my ball?

1/10th of the way from where the physics says it is in the current timestep, to where it says it will be in the next timestep.

To make this work, you still run the physics at a fixed rate, but make sure it is one ahead.

What you do is, have a counter that says "when" the last update occurred. When you draw, check the current time. Until the physics "catches up" and takes the lead, call update() and increment the "last-update-time" counter by the physics timestep. You need to save physics states corresponding to the update-times on either side of the "current rendering time", and interpolate accordingly.

Position ball_pos;Time last_physics = current_time();const DeltaTime timestep = FIFTY_MILLISECONDS;while (true) {  Time draw_time = current_time();  Position prev;  while (last_physics <= draw_time) {    prev = ball_pos;    Update(ball_pos);    last_physics += timestep;  }  // Interpolate from prev to ball_pos, with a distance proportional to  // time from the "previous" last_physics value until the draw_time.  // The bit after the * here represents what your reference calls "the  // accumulator".  Position render_pos = prev + (ball_pos - prev) *                         (draw_time - last_physics + timestep) / timestep;}

Errr... I think I got that right... :)

Of course, that's probably a quite different look at it from what your reference is saying, but I hope it clarifies the idea.

@raptorstrike: That's true for the case of circular motion, but *in the general case*, you can't get a formula that tells you exactly where to be - or at least, it would take at least as much time as re-calling the physics update() (plus you'd have to rework it to accept a "partial" timestep as well).

Share on other sites
OK. I think I understand... the key seems to be that the physics is 1-step ahead of rendering.

Two questions though:

1) Will this work OK for network/multiplayer games?

2) Will each object need custom code for this "tween" aka interpolation...? A projectile would be interpolated differently from a straight-moving object, right? Do I store this interpolated value or is it just used for rendering?

In the GarageGames Torque engine, they have three methods:

processTick()
interpolateTick()

If I used the same, would this logic seem correct: (?)

[ pseduo-code ]

while (true)
// physics updating
for each full tick inside accumulator
processtick()

// rendering
interpolateTick( amount_towards_next_tick ) // between 0 and 1

It seems like doing that means that interpolateTick replaces the typical Render() method. I don't understand how you could use both unless interpolateTick stores it's result somewhere...

Also, how would advanceTime() factor into all of this? (supposedly it's used for animations and it's called once per frame)