I'm implementing an FPS cap for my game, but it's not very precise.
public static volatile int FPS_CAP = 60;
@Override
public void run() {
long lastTime = System.nanoTime();
double amountOfTicks = 60.0;
double ns = 1000000000 / amountOfTicks;
double delta = 0;
long timer = System.currentTimeMillis(), lastRender;
while (running) {
long now = System.nanoTime();
delta += (now - lastTime) / ns;
lastTime = now;
while (delta >= 1) {
tick();
delta--;
}
lastRender = System.currentTimeMillis();
draw.render();
draw.fps++;
if (FPS_CAP != -1) {
try {
int nsToSleep = (int) ((1000 / FPS_CAP) - (System.currentTimeMillis() - lastRender));
if (nsToSleep > 1 / FPS_CAP) {
Thread.sleep(nsToSleep);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (System.currentTimeMillis() - timer > 1000) {
timer += 1000;
draw.lastFPS = draw.fps;
draw.fps = 0;
// updates = 0;
}
}
}
The result is:
As you can see it's really not accurate, sometimes it's a lot lower than 60 and sometimes even higher!
I want it to be as precise as possible.
Thanks in advance.
First of all I see you mixed System.currentTimeMilis()
and System.nanoTime()
not really a good idea, use only either one of them. Better only use System.nanoTime()
since you are working on a high precision.
What's causing your issue is Thread.sleep()
is not precise enough. So you need to avoid sleeping. Change your sleeping code to this;
lastRender = System.nanoTime(); //change it to nano instead milli
draw.render();
draw.fps++;
if (FPS_CAP > 0) {
while ( now - lastRender < (1000000000 / FPS_CAP))
{
Thread.yield();
//This stops the app from consuming all your CPU. It makes this slightly less accurate, but is worth it.
//You can remove this line and it will still work (better), your CPU just climbs on certain OSes.
//FYI on some OS's this can cause pretty bad stuttering.
try {Thread.sleep(1);} catch(Exception e) {}
now = System.nanoTime();
}
}
About how to enable VSYNC
, your application need to be full screen and you should call Toolkit.sync()
after every render.