游戏循环停顿

时间:2019-03-20 19:47:08

标签: java

我是Java的初学者。我试图用Swing创建一个简单的程序,其中有许多球在弹跳。程序运行良好,流畅60 fps,没有断断续续。但是,CPU始终以20%的速度运行。后来我读到某个地方,可以通过在循环末尾添加Thread.sleep方法来限制CPU使用率。但是,如果这样做,程序有时会结结巴巴。我不知道为什么,我什么都没改变。即使我长时间运行程序,它也不会总是停顿,有时甚至根本不会停顿。但是有时候,一旦我打开程序,它就会开始卡住。同样,当口吃时,FPS仍然显示60。那么我做错了什么吗?

这是游戏循环:

    long currentTime;
    long lastTime = System.nanoTime();
    int targetFps = 60;
    int timePerTick = 1000000000 / targetFps;
    long delta = 0;
    long fpsTimer = 0;
    int fpsCounter = 0;

    while(running) {
        currentTime = System.nanoTime();
        delta += currentTime - lastTime;
        fpsTimer += currentTime - lastTime;
        lastTime = currentTime;
        if(delta >= timePerTick) {
            fpsCounter++;
            update();
            render();
            delta -= timePerTick;

        }
        if(fpsTimer >= 1000000000) {
            System.out.println("FPS: " + fpsCounter);
            fpsTimer = 0;
            fpsCounter = 0;
        }

        try {
            Thread.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

3 个答案:

答案 0 :(得分:1)

程序停顿的事实并不意味着您的fps较低。在这种情况下,这仅意味着您多次具有相同的帧(因为您使线程处于休眠状态,并且UI中没有任何更改)。

为什么结巴? 可能是因为上下文切换。 当您使线程进入睡眠状态时,系统可以将处理器“交给”其他任务X,并且重新运行代码需要花费超过1毫秒的时间,因为您的代码将在该任务X执行了一段时间后执行

您想做什么。 添加Thread.sleep(1)调用不是正确的选择。您需要确保代码能够运行并且UI会定期更新,以确保它在慢速和快速系统中的行为相同。您应该更详细地研究游戏循环。

编辑

我不是专家,但是@Sedrick在评论this链接中建议,该链接似乎可以解释您想要做什么以及如何做。

答案 1 :(得分:1)

您不应以每秒获取60帧为目标。相反,您应该争取每1/60秒获得1帧。

差异和您看到60FPS时滞的原因是,如果由于某种原因当前看到200ms时滞,您只需在剩余的800ms中渲染59帧。仍然达到60 FPS,但显然对体验没有意义。

您可以改为为每个帧分配〜16ms。如果一帧花费较少的时间,则其余时间请休眠。如果花费更多时间,请跳过render()进入下一帧(但保留update()除非您可以重写它以支持流畅的时间步长)。这样,您的FPS编号将更具代表性,并通过长期平均将它们隐藏起来,从而显示出您当前正在遮盖的所有各种调度和GC打GC。

答案 2 :(得分:0)

您应该使用Swing计时器,而不要编写自己的循环。