我是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();
}
}
答案 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计时器,而不要编写自己的循环。