tags:

views:

358

answers:

2

I'm trying to keep my game at 60fps, but I'm getting strange results from my code like "2-8000 fps" Why isn't this staying at 60?

public static void main(String[] args) {

        joglplat m = new joglplat();
        while(true){
         long startTime = System.nanoTime() / 1000000;
          try
      {
       //                 123456: 6 zeros => 16ms
       long nsToSleep = 16000000 - (System.nanoTime() - lastFrame);
       System.out.println("ns: " + nsToSleep);
       lastFrame = System.nanoTime();

       if(nsToSleep > 0)
       {
          System.out.println("ns2: " + (nsToSleep/1000));
          System.out.println("ns3: " + (nsToSleep%1000));
          Thread.sleep(nsToSleep/16000000, (int)(nsToSleep % 1000));
       }
       else
       {
          Thread.yield();  // Only necessary if you want to guarantee that
                           // the thread yields the CPU between every frame
       }

      }

         catch(Exception e){
          e.printStackTrace();
         }

         m.controls();
         m.update();
         m.repaint();
         System.out.println("framerate: " + (System.nanoTime() / 1000000  - startTime));
        }
    }
+1  A: 

My suspicion is that this is caused by the inaccuracy of Thread.sleep():

Causes the currently executing thread to sleep (cease execution) for the specified number of milliseconds plus the specified number of nanoseconds, subject to the precision and accuracy of system timers and schedulers. The thread does not lose ownership of any monitors.

Is there any reason why you have to hold the framerate down like this? Perhaps you can explain more fully what you are trying to accomplish?

jsight
+1  A: 

Your output is the number of seconds your program has run for, not framerate. You should be dividing your frame count (which you aren't collecting) by the total time run.

To get the frame count, simply add a new variable outside of your game loop, and increment it each time through...

public static void main(String[] args) {
    long frames = 0;
    joglplat m = new joglplat();
    while(true){
        frames++;
        // other code here
        System.out.println("framerate: " + ((System.nanoTime() / 1000000  - startTime) / frames ) );
    }
}

Note, however, that this will give you the average framerate throughout the entire execution of your program. Two other options you have are to get the instantaneous framerate, and the average framerate over the past N frames.

All styles in one (untested/uncompiled, so might have some errors, but should get you started in the right direction):

public static void main(String[] args) {
    long startTime = System.nanoTime();
    long lastFrameTime = startTime;
    long frames = 0;
    int framesToAverage = 10;
    long[] frameTimes = new long[framesToAverage];
    joglplat m = new joglplat();
    while(true){
        // logic here
        long currentFrameDuration = System.nanoTime() - lastFrame;
        lastFrameTime = System.nanoTime();
        long instantFramerate = currentFrameDuration / 1000000;
        int currentFrameIndex = frames % frameTimes.length;
        frameTimes[currentFrameIndex] = currentFrameDuration;
        frames++;
        long averageFramerate = ( ( lastFrameTime - startTime) / frames ) / 1000000;
        long instantFramerate = currentFrameDuration / 1000000;
        if( frames > frameTimes.length ) { // if it isn't, we don't have enough data yet
            int firstFrameIndex = currentFrameIndex + 1;
            if( firstFrameIndex > frameTimes.length ) {
                firstFrameIndex = 0;
            }
            long averageFrameratePerN = ( ( frameTimes[currentFrameIndex] - frameTimes[firstFrameindex] ) / frameTimes.length ) / 1000000;
        }

        // yield/sleep here
    }
}
Illandril
Where do I collect the frame count? and how?
William
I have updated the answer with a bit more information
Illandril