0
\$\begingroup\$

I'm developing a Breakout style game in C++ using SDL. The problem so far is that the ball slows down and speeds up for no particular reason.

The slowdowns usually last a few seconds.

EDIT : When running fullscreen I noticed that the ball movement seems to be a tiny bit jerky as well. This leads me to believe that the timing should be more finely granulated. But at the same time, it shouldn't be necessary to have µs precision...

Here is my code for calculation the movement of the ball :

double deltaMovement = tick * speed;

rect.x += static_cast<int> ( deltaMovement * dirX );
rect.y += stnecessearyatic_cast<int> ( deltaMovement * dirY );

I tried changing it to help prevent float to in truncation, but this affects the speed to much, making the ball move only move horizontally or vertically ( which never happens with the above code. )

double movementX = ( deltaMovement * dirX );
double movementY = ( deltaMovement * dirY );

movementX += ( movementX > 0.0f )? 0.5f: -0.5f;
movementY += ( movementY > 0.0f )? 0.5f: -0.5f;

rect.x += static_cast<int> ( movementX );
rect.y += static_cast<int> ( movementX );

rect is an SDL_Rect and holds the ball's position. dirX and dirY are double and holds the direction of the ball, the values range from -1.0 to 1.0

I'm not sure if the issue is with the float to int conversion. I guess it could also be something with SDL internally, but I am quite sure SDL should be capable of smooth animation.


Here's my main game loop ( I have removed some irrelevant parts of it ) while ( !quit ) { while ( SDL_PollEvent( &event ) ) { // Handle input, move paddle, check if user pressed esc // Yes I have a means of escaping the outer while loop. } double delta = timer.GetDelta( );

    // Update the ball, check for collisions with wall/paddle/tiles
    UpdateBalls( delta );

    // Redraws everything    
    UpdateGUI();
}


I'm quite sure the issue is not with my delta time, since it's fairly consistant at 1 - 4 msec. And even if it did change a lot, it shouldn't matter. But just in case, here's the code I use for calculating delta time :

double Timer::GetDelta( )
{
    timespec tmCurrent;
    clock_gettime( CLOCK_MONOTONIC_RAW, &tmCurrent);

    // Get current time in nanoseconds
    unsigned long long deltaCurrent = static_cast< unsigned long long > ( tm.tv_sec * 1000000000 + tm.tv_nsec );

    // Get diff. Delta is an unsigned long long that holds previous tick ( see below)
    unsigned long long diff = deltaCurrent - delta;

    // Convert into ms and assign to a double
    double deltaMSec = static_cast< float > ( diff / 1000000.0f );

    // Reset delta so that it can be used the next time delta is calculated
    delta = deltaCurrent;

    return deltaMSec;
}


What am I doing wrong?

\$\endgroup\$
6
  • \$\begingroup\$ Where are deltaCurrent and delta coming from? If you've copy-pasted your timing code, then you're not updating the right variables. \$\endgroup\$ Aug 26, 2013 at 15:41
  • \$\begingroup\$ @ShotgunNinja A copy-paste mistake. I have updated the question now. \$\endgroup\$
    – olevegard
    Aug 26, 2013 at 15:51
  • \$\begingroup\$ Wow, that is an extremely unportable way of doing timing. If you want to be more portable, gettimeofday (...) provides enough resolution and granularity on all major *UX platforms your game is likely to run on (OS X, Linux, BSD). You should also use double-precision instead of single-precision FP for the deltaMSec. \$\endgroup\$ Aug 27, 2013 at 1:21
  • 1
    \$\begingroup\$ Portbillity is not an issue right now. My plan was to add #ifdefs to add support for other platforms. Also gettimeofday (...) seems to be hardware dependant : lehman.cuny.edu/cgi-bin/man-cgi?gettimeofday+3 I will change resolution to double, though. \$\endgroup\$
    – olevegard
    Aug 27, 2013 at 7:41
  • 1
    \$\begingroup\$ clock_gettime (...) is also hardware-dependent. The only condition it adds (when using MONOTONIC) is that the value returned is always non-decreasing. This avoids issues with rdtsc-like instructions when the thread your timer is running on changes scheduled processors. However, despite being POSIX, it is not implemented on platforms like OS X. Also, MONOTONIC_RAW is a Linux-only extension. \$\endgroup\$ Aug 27, 2013 at 19:49

1 Answer 1

3
\$\begingroup\$

I don't think your issue is timing related. If you change your object velocity so that the amount of movement per update is very low (i.e. less than 0.5 units per update) my guess is that your object will never move at all!

Currently, you are tracking a moving position over time as an integer (SDL_Rect is integer based). Any fractional movement associated with each update is lost due to the casting to an integer. Over time, these missing fractional movements add up and lead to jittery, non-smooth movement of the object overall. This is especially obvious for slower moving objects where the rounding doesn't average out as well and the discarded fractional portion represents a larger part of the overall movement.

The solution is to track your positions in floating point coordinates, then convert to integer coordinates only when rendering.

\$\endgroup\$
2
  • \$\begingroup\$ I created my own struct that's basically the same as SDL_Struct but with double instead of short for storing position / dimension. It seems to be working, now. Thank you! \$\endgroup\$
    – olevegard
    Aug 27, 2013 at 20:27
  • \$\begingroup\$ After some more testing it seems there's still issues. The ball moves smoothly, but it has random freezes where it slows down and stops completely before stopping. \$\endgroup\$
    – olevegard
    Aug 28, 2013 at 9:21

You must log in to answer this question.

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