帧速率代码得到奇怪的结果

时间:2022-01-26 08:21:39

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?

我试图保持我的游戏速度为60fps,但是我的代码变得奇怪,比如“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));
        }
    }

2 个解决方案

#1


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.

但请注意,这将为您提供整个程序执行期间的平均帧速率。另外两个选项是获得瞬时帧率,以及过去N帧的平均帧率。

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

#2


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

我怀疑这是由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?

你有必要像这样保持帧率吗?也许你可以更全面地解释你想要完成的事情?

#1


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.

但请注意,这将为您提供整个程序执行期间的平均帧速率。另外两个选项是获得瞬时帧率,以及过去N帧的平均帧率。

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

#2


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

我怀疑这是由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?

你有必要像这样保持帧率吗?也许你可以更全面地解释你想要完成的事情?