Saturday, November 08, 2008

Speed UP! Slooooow down....

So, it turns out the Java compiler is fine (I think). My timing code (that makes the game run at a specific FPS) appears to be crippling things. But I have no idea how. If I take out my timing code and run the game unscaled it ticks along at 350fps - or 7 times the normal frame rate. It looks like thats correct too as everything is moving about 7x the speed, so I think the FPS counter is working.

So... whats wrong with my timing loop thats crippling it so much? I've tried to set and FPS of 200, but as soon as I do that, it tops out at 65fps. If I remove a couple of lines (the bit that makes it work), it jumps up to 350 again. So somethings rotten right in the state of Denmark... So, heres the timing loop, perhaps someone out there will spot it and save me staring at boring code for hours on end.....


long tLastGameFrame = System.currentTimeMillis();
long tNextGameFrame = tLastGameFrame + FPSRate;

Last = tLastGameFrame;
while (true)
{
long tNow = System.currentTimeMillis();

// Quick check to see it timer has gone backwards!!
if( tNow < tLastGameFrame ){
tLastGameFrame= tNow;
}

// Check to see if system is stuttering due background OS stuff.
// if jumped ahead over 5 seconds, then just reset...
if( (tNow-tNextGameFrame) > 5000 ){
tNextGameFrame = tNow;
}

// Timer has gone backwards
if( tNow < tLastGameFrame ){
tLastGameFrame= tNow;
}


dTime = (int)(tNow - Last);
if (dTime >= 1000){
dTime -= 1000; // dont get 0 (1000/1001)
actualfps = CurrentFPSCount;
CurrentFPSCount=0;
Last = tNow;
}

// Now the main timing loop
if( tNextGameFrame >= tNow )
{
// do nothing...or yield/sleep
} else
{
while( tNow>tNextGameFrame){
tLastGameFrame = tNextGameFrame;
tNextGameFrame += FPSRate;
}
CurrentFPSCount++;
}


And there you go... pretty simple. Oh, and the reason for the backwards check is because in the modern world of clock syncing (to time.com or something), your clock might briefly go backwards. If this happens timer loops break - had this happen twice! Once on mobile phones, and once on a PC. Took me AGES to figure out the Mobile phone one, but fortunately I remembered about it for the PC.

4 comments:

Dave Shadoff said...

I think you might find that the current time in milliseconds is not real-time, but rather has granularity issues.

You may recall from eons ago that the PC has a 16ms interrupt for the real-time clock (approx 65 times per second)... this is something which could have changed over the years but really didn't.

There is probably a much better interface to get the system time from, but as I recall it would rely on technologies that JAVA doesn't want to rely on.

Here's a test: write a loop which grabs the current time in milliseconds, and logs it; watching carefully for changes. I expect you'll see SAME, SAME, SAME, 16ms jump, SAME, etc.

Dave Shadoff said...

As a follow-up to that, this seems to be a Windows thing, not a PC thing.

You should probably use System.nanoTime()/1000000 instead of System.currentTimeMillis().

Or don't use Windows.

See article:
http://www.simongbrown.com/blog/2007/08/20/millisecond_accuracy_in_java.html

Mike said...

Yep,... just figured this out too... Since frames were taking either 0ms or 15ms - which is classic windows GetTime() stuff.

I was just about to look for a better time so thanks for pointing me in the right direction! :)

Mike said...

Ahhhh!! Much better!! Thanks guys!

I do wish M$ would do the decent thing and fix GetTime()....