Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I'm trying to implement the game loop where the physics is independent from rendering but my animation isn't as smooth as I would like it to be and it seems to periodically jump. Here is my code:

// alpha is used for interpolation
double alpha = 0, counter_old_time = 0;
double accumulator = 0, delta_time = 0, current_time = 0, previous_time = 0;
unsigned frame_counter = 0, current_fps = 0;

const unsigned physics_rate = 40, max_step_count = 5;
const double step_duration = 1.0 / 40.0, accumulator_max = step_duration * 5;

// information about the circ;e (position and velocity)
int old_pos_x = 100, new_pos_x = 100, render_pos_x = 100, velocity_x = 60;

previous_time = al_get_time();

while(true) {
    current_time = al_get_time();
    delta_time = current_time - previous_time;
    previous_time = current_time;
    accumulator += delta_time;

    if(accumulator > accumulator_max) {
        accumulator = accumulator_max;
    }

    while(accumulator >= step_duration) {
        if(new_pos_x > 1330) velocity_x = -15;
        else if(new_pos_x < 70) velocity_x = 15;

        old_pos_x = new_pos_x;
        new_pos_x += velocity_x;
        accumulator -= step_duration;
    }

    alpha = accumulator / static_cast<double>(step_duration);
    render_pos_x = old_pos_x + (new_pos_x - old_pos_x) * alpha;

    al_clear_to_color(al_map_rgb(20, 20, 40)); // clears the screen
    al_draw_textf(font, al_map_rgb(255, 255, 255), 20, 20, 0, "current_fps: %i", current_fps); // print fps
    al_draw_filled_circle(render_pos_x, 400, 15, al_map_rgb(255, 255, 255)); // draw circle
    // I've added this to test how the program will behave when rendering takes
    // considerably longer than updating the game.
    al_rest(0.008);
    al_flip_display(); // swaps the buffers

    frame_counter++;

    if(al_get_time() - counter_old_time >= 1) {
        current_fps = frame_counter;
        frame_counter = 0;
        counter_old_time = al_get_time();
    }
}

I have added a pause during the rendering part because I wanted to see how the code would behave when a lot of rendering is involved. Removing it makes the animation smooth but then I'll have to make sure that I don't let the frame rate drop too much and that doesn't seem like a good solution. I've been trying to fix this for a week and have had no luck so I'd be very grateful if someone can read through my code. Thank you!

Edit: I added the following code to work out the actual velocity (pixels per second) of the ball each time the ball is rendered and surprisingly it's not constant so I'm guessing that's the issue. I'm not sure why it's not constant.

alpha = accumulator / static_cast<double>(step_duration);
render_pos_x = old_pos_x + (new_pos_x - old_pos_x) * alpha;
cout << (render_pos_x - old_render_pos) / delta_time << endl;
old_render_pos = render_pos_x;
share|improve this question
    
What about changing render_pos_x = old_pos_x + (new_pos_x - old_pos_x) * alpha; into render_pos_x = new_pos_x + (new_pos_x - old_pos_x) * alpha;? If I'm correct, new_pos_x is the last position you calculated, so the extrapolation should start from there. –  ph4nt0m Jul 28 '13 at 18:42
    
I just tried that and it didn't help :( Also, I'm interpolating instead of extrapolating. –  sythical Jul 28 '13 at 19:12

2 Answers 2

@ph4nt0m's answer is probably the fix to your problem.

Another potential issue you're seeing is that the physics are simple too coarse. You can try increasing the rate of physics iterations (reduce step_duration). Your current duration is only 40Hz, so the game is going to look choppy compared to many 60Hz games, especially as 40 does not evenly divide into 60 (some render frames will see a physics update, some won't). Consider running at >=60Hz for physics, or sticking to 20 or 30 or another number that divides evenly into 60.

Yet another more complicated fix, necessary in "higher end" games, is to interpolate between physics updates. You store the previous physics state and the current one calculated at each physics step. You then use the raw delta_time to interpolate between these two states during rendering. This lets you get away with a longer interval between physics updates and adds a mostly negligable overhead to rendering if done intelligently. The support for interpolation here comes in handy for network support, too.

share|improve this answer

I think that the following part of your code is problematic:

if(accumulator > accumulator_max) {
    accumulator = accumulator_max;
}

You are basically doing a clamp() here, saying that every time difference which exceeds five steps should be disregarded, since

accumulator_max = step_duration * 5;

Should one iteration of your game loop require more than 0.125 seconds, your code will ignore this and move your objects not as far as it should do according to the real time difference.

share|improve this answer
    
Don't actually all tutorials tell us to clamp the accumulator? Even in the classical "Fix your timestep" Glenn uses: if ( frameTime > 0.25 ) frameTime = 0.25; Which is nothing but clamping. –  Devdalus Jul 28 '13 at 15:12
    
You're right, that's to avoid the "spiral of death", but the price is that you allow the simulation to slow down when required. It's obvious that the 0.25 value has to be chosen wisely. If you set it too low, the accumulator will exceed it quite regularly, which could well be the reason for "unsmooth" or jumping animations. Unfortunately, sythical didn't give any details about the framerate for example, but the fact that removing the pause solves the problem indicates that this could be the reason. –  ph4nt0m Jul 28 '13 at 15:27
    
I was suspicious of this part as well and have tried removing it but it had no effect. The frame rate I'm getting is around 125 with the pause, 6000 without the pause. I calculated the distance that the ball moves between two renders and divided it by the delta_time to work out the velocity of the ball. Surprisingly, the velocity wasn't constant and would normally be 600 and then just to 700. Not sure why this happens. –  sythical Jul 28 '13 at 17:51

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.