I am building a game with a good emphasis on physics. Therefore I need the game to run on a very specific interval. Current code:
public double period = .02; //this is the run interval in seconds
//main gameLoop
public void gameLoop(){
long startTime;
long sleep;
while(running){
startTime = System.nanoTime();
Graphics2D g = s.getGraphics();
operateEntities(g);
g.dispose();
s.update();
//figure out how long it must sleep to take .02s altogether
sleep = ((int)(period*1000) - (System.nanoTime() - startTime)*100000);
try{
if(sleep > 0){
Thread.sleep(sleep);
}else{
System.err.println("Warning: program runtime exceeded period");
}
}catch(Exception ex){}
gameTime += period;
}
}
This is not working as expected. Currently the main thread is executing without sleeping at all, and the “Warning: program runtime exceeded period” warning is firing.
Previously I was using System.currentTimeMillis(), but it was not accurate enough for my purposes, so I switched to System.nanoTime()
Increasing the period actually serves to speed up the program, while reducing it slows it down.
Is there a simple logic faw? is my understanding of System.nanoTime() off? or is there a better way to run the methods operateEntities, dispose, and update on a specific interval?
EDIT: for the record, the program does not take more than .02s to complete. It has been tested
Breaking down your code there are a number of problems:
This code will always error out unless you make your
periodvalue much larger. However, even beyond that your approach will not likely yield the result you want: accurate timing. What your core loop is:With a small enough time slice this will be accurate. However, threads don’t work like that. You cannot guarantee when the thread will wake up. It could be never. It could be in three seconds. It could be instantly. Chances are you’re going to overshoot whatever your time period is, and you will effectively never hit it dead on.
Instead of relying on a specific incremental period, you need to scale all your physics by the period of time that has actually passed, rather than rely on a specific period of time passing consistently every time.
You still want a small time slice to sleep, but this way you eliminate the error introduced by the thread scheduler.