My rhythm game runs choppy even with high frame rate
- by felipedrl
I'm coding a rhythm game and the game runs smoothly with uncapped fps. But when I try to cap it around 60 the game updates in little chunks, like hiccups, as if it was skipping frames or at a very low frame rate. The reason I need to cap frame rate is because in some computers I tested, the fps varies a lot (from ~80 - ~250 fps) and those drops are noticeable and degrade response time. Since this is a rhythm game this is very important.
This issue is driving me crazy. I've spent a few weeks already on it and still can't figure out the problem. I hope someone more experienced than me could shed some light on it. I'll try to put here all the hints I've tried along with two pseudo codes for game loops I tried, so I apologize if this post gets too lengthy.
1st GameLoop:
const uint UPDATE_SKIP = 1000 / 60;
uint nextGameTick = SDL_GetTicks();
while(isNotDone)
{
// only false when a QUIT event is generated!
if (processEvents())
{
if (SDL_GetTicks() > nextGameTick)
{
update(UPDATE_SKIP);
render();
nextGameTick += UPDATE_SKIP;
}
}
}
2nd Game Loop:
const uint UPDATE_SKIP = 1000 / 60;
while (isNotDone)
{
LARGE_INTEGER startTime;
QueryPerformanceCounter(&startTime);
// process events will return false in case of a QUIT event processed
if (processEvents())
{
update(frameTime);
render();
}
LARGE_INTEGER endTime;
do {
QueryPerformanceCounter(&endTime);
frameTime = static_cast<uint>((endTime.QuadPart - startTime.QuadPart) * 1000.0 / frequency.QuadPart);
} while (frameTime < UPDATE_SKIP);
}
[1] At first I thought it was a timer resolution problem. I was using SDL_GetTicks, but even when I switched to QueryPerformanceCounter, supposedly less granular, I saw no difference.
[2] Then I thought it could be due to a rounding error in my position computation and since game updates are smaller in high FPS that would be less noticeable. Indeed there is an small error, but from my tests I realized that it is not enough to produce the position jumps I'm getting. Also, another intriguing factor is that if I enable vsync I'll get smooth updates @60fps regardless frame cap code. So why not rely on vsync? Because some computers can force a disable on gfx card config.
[3] I started printing the maximum and minimum frame time measured in 1sec span, in the hope that every a few frames one would take a long time but still not enough to drop my fps computation. It turns out that, with frame cap code I always get frame times in the range of [16, 18]ms, and still, the game "does not moves like jagger".
[4] My process' priority is set to HIGH (Windows doesn't allow me to set REALTIME for some reason). As far as I know there is only one thread running along with the game (a sound callback, which I really don't have access to it). I'm using AudiereLib. I then disabled Audiere by removing it from the project and still got the issue. Maybe there are some others threads running and one of them is taking too long to come back right in between when I measured frame times, I don't know. Is there a way to know which threads are attached to my process?
[5] There are some dynamic data being created during game run. But It is a little bit hard to remove it to test. Maybe I'll have to try harder this one.
Well, as I told you I really don't know what to try next. Anything, I mean, anything would be of great help. What bugs me more is why at 60fps & vsync enabled I get an smooth update and at 60fps & no vsync I don't. Is there a way to implement software vsync? I mean, query display sync info?
Thanks in advance. I appreciate the ones that got this far and yet again I apologize for the long post.
Best Regards from a fellow coder.