Jump to content

  • Log In with Google      Sign In   
  • Create Account


Trouble making my animation smooth


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
13 replies to this topic

#1 Sythical   Members   -  Reputation: 138

Like
0Likes
Like

Posted 28 July 2013 - 01:56 PM

Hello, 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. The animation periodically jumps forward and I have no idea why this is happening. Here is my code:

.

// alpha is used for interpolation
// counter_old_time is to do with displaying the fps
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; // also used for displaying the fps
const unsigned physics_rate = 40, max_step_count = 5;

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

const double
    step_duration       = 1.0 / 40.0,
    accumulator_max     = step_duration * 5;

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 tried remove the clamp (that avoids the spiral of death) and checked my interpolation method but had no luck so I'd be very grateful if someone can have a look at this. Thank you!



Sponsor:

#2 Felipe Such   Members   -  Reputation: 110

Like
0Likes
Like

Posted 28 July 2013 - 07:40 PM

Try instead of while(accumulator >= step_duration) if(accumulator >= step_duration).

That is not a solution. But it can help us find the problem.



#3 Sythical   Members   -  Reputation: 138

Like
0Likes
Like

Posted 28 July 2013 - 09:29 PM

Thank you for the suggestion. Just tried that and it made no difference. With the pause, my frame rate is around 125 so the physics is updated once for every 2 to 3 renders.



#4 Felipe Such   Members   -  Reputation: 110

Like
0Likes
Like

Posted 28 July 2013 - 11:05 PM

Well, if that made no difference I would guess that this is the problem:

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

try just:

render_pos_x = new_pos_x;



#5 NumberXaero   Prime Members   -  Reputation: 1312

Like
0Likes
Like

Posted 28 July 2013 - 11:22 PM

Using the alpha to render is the whole point of doing the loop this way. Try "new_pos_x += velocity_x * delta_time;" in the inner loop. See if anything changes.


Edited by NumberXaero, 28 July 2013 - 11:22 PM.


#6 Sythical   Members   -  Reputation: 138

Like
0Likes
Like

Posted 28 July 2013 - 11:52 PM

Using the alpha to render is the whole point of doing the loop this way. Try "new_pos_x += velocity_x * delta_time;" in the inner loop. See if anything changes.

 

delta_time is in seconds and it's usually about 0.00-something so making that change just makes the circle stay still. Changing the type of the position variables to double makes the circle move ever so slightly.



#7 SuperVGA   Members   -  Reputation: 1118

Like
0Likes
Like

Posted 29 July 2013 - 05:02 AM

Does the framerate change drastically? Because i suspect you only compute fps once a second,
and only fairly steady framerates will produce animations with no speed jitter when they like this.

 

(Consider using framerate-independent timing if the above is the case)



#8 Sythical   Members   -  Reputation: 138

Like
0Likes
Like

Posted 29 July 2013 - 01:03 PM

My framerate varied between 58 and 62 and I was told on the Allegro forum that this is normal and I should  calculate the average instead. When playing games, I notice that the FPS changes a lot and so I assumed that games still look smooth even if the FPS isn't completely steady.

 

And... I thought I was already using frame rate independent timing? :(



#9 Pink Horror   Members   -  Reputation: 1091

Like
0Likes
Like

Posted 29 July 2013 - 08:28 PM

What happens when you increase step duration? Try something crazy like 2.0 instead of 1.0/40.0.

 

Note that we're all shooting in the dark without actually seeing the bug.



#10 Sythical   Members   -  Reputation: 138

Like
0Likes
Like

Posted 30 July 2013 - 10:52 AM

Sorry, I tried recording the bug but it introduced extra lag and the actual issue wasn't clearly visible in the video. Changing step duration to 2.0 makes the animation very slow and it's a little bit smoother.

 

I may have discovered the issue: after swapping the buffers, I started printing the time difference between the swap that just happened and the previous swap. It normally prints 0.008s and 0.009s but 0.01s are quite frequent so maybe this is causing the animation to not look as smooth? I found out that Allegro has vsync option and enabling that made the animation very smooth. From the output, I got 0.016s with occasional 0.0017s which is a lot more even.



#11 Pink Horror   Members   -  Reputation: 1091

Like
0Likes
Like

Posted 30 July 2013 - 12:04 PM

Right, I thought maybe if the animation is very slow you'll catch the issue.

 

It sounds like your smoothness issue might have been from having different amounts of progress between each vsync. There isn't a big difference between 0.008s and 0.01s, so I don't think that's the issue. But I have are guesses.

 

Well, getting away from caring about framerate beyond vsync is a good thing, in my opinion. I'm glad you got that out of the way early.



#12 SuperVGA   Members   -  Reputation: 1118

Like
0Likes
Like

Posted 30 July 2013 - 02:01 PM

My framerate varied between 58 and 62 and I was told on the Allegro forum that this is normal and I should  calculate the average instead. When playing games, I notice that the FPS changes a lot and so I assumed that games still look smooth even if the FPS isn't completely steady.

 

And... I thought I was already using frame rate independent timing? sad.png

If you measure the framerate once a second, and base your timing off that it's not accurate and certainly not frame rate independent.

The 62-80 seem rather low and I don't suspect that's actually the reason. Of course it's all a matter of scale.

 

Also, this statement is rather pedantic. If the framerate is around a certain number, if you sample right and often, or if the framerate is locked,

timing based on fps is fine.



#13 Sythical   Members   -  Reputation: 138

Like
0Likes
Like

Posted 30 July 2013 - 04:08 PM

If you measure the framerate once a second, and base your timing off that it's not accurate and certainly not frame rate independent.

 

I get the current time at the start of each frame and use it for doing the physics. The FPS counter is completely seperate so I don't think it has an effect on the physics.

 

Well, getting away from caring about framerate beyond vsync is a good thing, in my opinion. I'm glad you got that out of the way early.

 

When trying to figure out how to use vsync in SDL, I was told that vsync doesn't work in windowed mode since the draws are managed by the OS. If I modify the program to use SFML instead of Allegro, vsync doesn't work and the animation is not smooth so I feel that using Allegro's vsync is kind of cheating and not an actual solution (since if I decide to switch to SDL and SFML the problem will show up again).

 

It sounds like your smoothness issue might have been from having different amounts of progress between each vsync.

 

Yes, that's what I'm thinking as well so I'll try and figure out if there is a way to solve this.


Edited by Sythical, 30 July 2013 - 04:09 PM.


#14 Pink Horror   Members   -  Reputation: 1091

Like
0Likes
Like

Posted 30 July 2013 - 06:36 PM


When trying to figure out how to use vsync in SDL, I was told that vsync doesn't work in windowed mode since the draws are managed by the OS. If I modify the program to use SFML instead of Allegro, vsync doesn't work and the animation is not smooth so I feel that using Allegro's vsync is kind of cheating and not an actual solution (since if I decide to switch to SDL and SFML the problem will show up again).

 

I just mean that I don't put much care into framerates that are faster than what my monitor can handle. I wouldn't use extra CPU just to draw a bunch of invisible frames.






Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS