0
\$\begingroup\$

I am working in a simple bouncing ball game. The ball moves right to left at a constant speed and back when it collides with the border of the display. But it jumps every time the the user clicks and then it falls. I apply no friction or something of that kind so when the ball bounces it has to have the exact opposite speed it had when it collided, but due to acceleration, when the frame rate is low it accelerates more than it should and bounces at a greater speed (and higher position), and when the frame rate is too high it bounces at a lower speed (and lower position). This obviously doesn't affect horizontal movement because there is no acceleration in there.

double current_time = SDL_GetTicks();
//for my convenience this is global variable
deltaTime = current_time - *previous_time;
*previous_time = current_time;

//Apply motion in x and y
ball.x += ball.x_speed * deltaTime / 1000;
ball.y += ball.y_speed * deltaTime / 1000;

//Accelerate
//Not quite sure where this should go for physical correctness
ball.y_speed += 1.5 * deltaTime;

ball.rect.x = (int) ball.x;
ball.rect.y = (int) ball.y;

So I now want to know how to make the speed be constant even if the frame rate isn't when I collide with the ground (obviously without getting rid of gravity acceleration).

Update

I didn't find any other relevant code to show you but I will provide a broader look at how I process and display the objects in the game.

I am using SDL to create this game. So I create this struct as a game object:

typedef struct PHYS_Object
{
    SDL_Rect collider;
    int x_speed, y_speed;
    //These two are the exact position of the object
    double x, y;
    int usesGravity;
    SDL_Texture* sprite;
}PHYS_Object;

Then in the main function before entering the main loop I create the objects and provide all the needed information like the image it's gonna use, the position etc... and store the objects that move in an array and objects that collide in other array (some of them are in both).

then in the main loop it goes like this:

//Abbreviated code
while(!quit)
{
    if(is_clicked(&button_1))
    {
        react_to_click();
    }else if(is_clicked(&button_2))
    {
        react_to_click();
    }else if(is_clicked(&play_button))
    {
        ball.y_speed = -250;
    }

    //Now move all the objects in the array 
    //according to their speeds and position
    //See the code above
    PHYS_ApplyMotion(moving_objects_array);

    //Now detect and react appropriately to the
    //collisions produced after motion occurred 
    PHYS_DetectCollisions(colliding_objects_array);

    SDL_RenderClear(renderer);
    SDL_RenderCopy(everything);
    SDL_RenderPresent(renderer);
}
\$\endgroup\$

2 Answers 2

1
\$\begingroup\$

I believe the problem is that you're assuming that the ball is at a constant speed throughout the time step. The relevent parts of your code are:

ball.y += ball.y_speed * deltaTime / 1000;
ball.y_speed += 1.5 * deltaTime;

Unfortunately, this method only gives an approximation of the position, and this is why you are seeing errors. You are not taking into account the smooth speed variation between the last time step and this time step.

Fortunately, it's actually pretty easy to take this variation into account. The equation for distance travelled moving under a constant acceleration is:

s = ut + 0.5at2

Where s is the displacement, u the speed at the start of the time step, a the acceleration of the body and t the time step. In your case:

u = ball.y_speed;
t = deltaTime / 1000;
a = 15000;

So, to correct your problem you can use the following code:

ball.y += (ball.y_speed * deltaTime / 1000) + (0.5 * 15000 * ((deltaTime / 1000) * (deltaTime / 1000));
ball.y_speed += 15000 * deltaTime / 1000;

This should fix your issue.

\$\endgroup\$
4
  • \$\begingroup\$ I tried your answer but it just has the same result the ball bounces at irregular speeds and different heights each time, plus it oddly just shows down in the bottom of the screen instead of smoothly jumping and falling down like it did before. And a little doubt: why is a = 15000? \$\endgroup\$ Commented Nov 27, 2014 at 17:23
  • \$\begingroup\$ That's strange - without being able to look at it it's hard to say why. I've used a=15000 as you've been incosistant with your units in the original question, so there is some ambiguity: for acceleration you use deltatime, for speed you use deltatime / 1000. \$\endgroup\$
    – Jez
    Commented Nov 27, 2014 at 19:50
  • \$\begingroup\$ I'll try to find some other relevant code and post it as soon as I can to see if the problem is somewhere else. \$\endgroup\$ Commented Nov 27, 2014 at 20:03
  • \$\begingroup\$ I posted some extra code that might matter to identify the "bug" in my code \$\endgroup\$ Commented Nov 27, 2014 at 21:35
0
\$\begingroup\$

Try basing your calculations on system time if you want it to be non frame-rate dependent. The only thing I can say is that basing the movement calculations on frame-rate should mean that if the frame rate drops then then the ball should slow down with the frames. I have done something similar to this before and what I did is each gamestep or MainUpdate would update a tickRate variable and then if the application hung then anything that was dependent on the tickRate would run at the speed of the applications MainUpdate. This allows the graphics to drop frames or run at a variable framerate with no negative effects on performance. Though I'm sure deltaTime is based off of the main game loop which would mean variance in graphics frames shouldn't effect it.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .