game loop

Started by
14 comments, last by InferiorOlive 11 years, 4 months ago

According to this article interpolation is needed to avoid stuttering and this seems to be true because removing the interpolation doesn't help. Maybe I should use the next position instead of the previous. I dont see any error in the way i am calculating the interpolation yet the movement of the sprite is not smooth. I tried putting some sleep calls and it does minimize the stuttering but it doesn't eliminate it completely.


It seems like there's way too much going on to accomplish not very much.

Interpolation is not a magical cure-all. It's just selecting a position between two endpoints.

1+1+1+0.5 = 3.5

So there's no reason to run a loop that adds to your total 1+1+1 times and then manually implements the 0.5 in the rendering because it's the halfpoint lerp value between 0 and 1.

Figure out the position of your sprite and place it in that position then render it where it sits. What you're doing right now is finding a position near where the thing is and then using interpolation to try and make it look like it is where it belongs.

If you want to re-invent floating point division that's up to you I guess, but this code tells lies all over the place. Your delta is not a delta, your position is not a position, your Render() is actually RenderSomethingSimilarButNotQuite().

As for that article, if you need pinpoint precision for positioning then the Runge-Kutta method is appropriate, but if you just let the star's position be its actual position then Euler will give smooth motion without the need to reinvent floating point division. Gaffer is using double precision and RK4 because he's probably thinking about large values in a large space, but for 'pixel per second' you can just use 'normal' Euler math. His use of a fixed 'delta' in that code progression is very misleading. The delta was a delta in the earlier code, but by the time he gets to the end it's just a scalar value for the frame time. The reason he's using interpolation is because he's separating physics simulation steps at specific points. Honestly when he gets to 'accumulator < dt' he should then feed accumulator into the physics instead of carrying it over to the next frame. There's no reason to do that in the code you have here since pixel-width is not high granularity. If you avoid having velocities that are ridiculously high then you should be okay without having to spoon-feed the simulation.

Even if you want to keep the loop for collision test dragging just let the position be the position and do away with 'accumulator' and 'p' and the messy game of 'catch-up'. If you want to interpolate a pixel-per-second motion with interpolation then set your velocity in terms of PPS and then get your delta T and put it in terms of a fraction of a second then multiply it by your motion.

Did you implement single-motion first and then move on to dragging?

Pseudocode:
[source]whatTickIsIt(&nowTime);
ticksPassed = nowTime - prevTime;
prevTime = nowTime;
secondsPassed = ticksPassed / tickHz;
position.x += position.x + (velocity.x * secondsPassed);
if(outOfBounds) {
//stuff
}[/source]

Meanwhile, putting this all in linear order and extracting irrelevant code I think I may see what's causing your stutter.

Try this:

lerp = (float)accumulator / UPDATE_TICKS;

I really wish I had a compiler on this machine. A debugger makes it so much easier to find this kind of thing.
void hurrrrrrrr() {__asm sub [ebp+4],5;}

There are ten kinds of people in this world: those who understand binary and those who don't.
Advertisement
Khatharr, your pseudocode seem to suggest a variable time step which i have used in previous projects, and it works. The problem is if the game slows down a big delta time is passed to Update(), which may result in missed collisions.


Try this:

lerp = (float)accumulator / UPDATE_TICKS;


Doesnt help.
Yeah, you can break up the delta if the sim needs it. I'm saying don't carry over the fraction to the next frame. Just pass it in to the sim and start the next frame with a new delta.
void hurrrrrrrr() {__asm sub [ebp+4],5;}

There are ten kinds of people in this world: those who understand binary and those who don't.
Instead of

[source lang="cpp"]while( accumulator >= UPDATE_TICKS )[/source]

try

[source lang="cpp"]while( accumulator >= 0 )[/source]

And change accumulator to a signed int. Then, for any left over accumulator, you're running one update frame into the future, at which point the interpolation makes more sense.
After so much frustration this is what worked for me:



int accumulator = ( int )( ( ( tNow - tPrev ) * 1000 ) / tFreq );
tPrev = tNow;

while( accumulator > 0 )
{
Update( DELTA_TIME )
accumulator -= UPDATE_TICKS;
}

//Compensate for the extra update loop that consumes the remainder
if( accumulator != 0 ) Sleep( abs( accumulator ) );

Render();



And i removed the interpolation.
Thanks everyone.
I might be wrong, but I think your stuttering came from the fact that you're interpolating in the wrong direction. It looks like you're pushing your star backwards toward where it was at the last update instead of forward by the amount of time left over. The way it's set up looks like your render function should render the star where it would be a given amount of time after the last update call (make a prediction based on its current velocity) rather than where it was between the past two calls.

Like I said, I could be wrong (I just implemented something like this in my own game, and it seems to be working).

Inspiration from my tea:

"Never wish life were easier. Wish that you were better" -Jim Rohn

soundcloud.com/herwrathmustbedragons

This topic is closed to new replies.

Advertisement