0

我试图将我的游戏保持在 60 fps,但我的代码却得到了奇怪的结果,例如“2-8000 fps” 为什么不保持在 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));
        }
    }
4

2 回答 2

1

我怀疑这是由 Thread.sleep() 的不准确引起的:

使当前执行的线程休眠(停止执行)指定的毫秒数加上指定的纳秒数,具体取决于系统计时器和调度程序的精度和准确性。该线程不会失去任何监视器的所有权。

有什么理由必须像这样保持帧率吗?也许您可以更全面地解释您要完成的工作?

于 2009-04-20T15:55:55.863 回答
1

您的输出是程序运行的秒数,而不是帧率。您应该将帧数(您没有收集)除以总运行时间。

要获得帧数,只需在游戏循环之外添加一个新变量,然后每次通过...

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 ) );
    }
}

但是请注意,这将为您提供整个程序执行过程中的平均帧速率。您还有两个选择是获得瞬时帧率和过去 N 帧的平均帧率。

所有样式合二为一(未经测试/未编译,因此可能会有一些错误,但应该让您朝着正确的方向开始):

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
    }
}
于 2009-04-20T16:01:54.210 回答