I'm creating a simple Java game engine (just for fun). The idea is to create a basic framework for developing any kind of 2D game, an abstract engine that does the hard work. Would you like to review the core of it and give me some tips?
GameTimer class:
public class GameTimer {
public static final double ONE_SECOND = java.util.concurrent.TimeUnit.SECONDS.toNanos(1);
private long start;
private long[] ticks = new long[1000];
private int first, last;
private int fps;
public GameTimer(){}
public void start(){
this.start = System.nanoTime();
}
public void tick(){
ticks[last] = System.nanoTime();
while (ticks[last] - ticks[first] > ONE_SECOND){
first = circular(first + 1);
fps--;
}
last = circular(last + 1);
fps++;
}
public long tock(){
return System.nanoTime() - ticks[circular(last-1)];
}
public long getElapsedNanoTime(){
long prev = ticks[circular(last-2)];
return (prev == 0) ? 0 : ticks[circular(last-1)] - prev;
}
public double getElapsedTime(){
return this.getElapsedNanoTime() / ONE_SECOND;
}
public long getNanoTime(){
return System.nanoTime() - this.start;
}
public double getTime(){
return this.getNanoTime() / ONE_SECOND;
}
public int getFPS(){
return this.fps;
}
private int circular(int n){
return Math.floorMod(n, ticks.length);
}
}
Game loop:
double desiredFPS = 60d;
long sleep = (long) (GameTimer.ONE_SECOND / desiredFPS);
GameTimer timer = new GameTimer();
timer.start();
try {
while(true){
// tick and print fps
timer.tick();
System.out.println(timer.getFPS());
// input, update and draw (abstract methods of my engine class)
input();
update();
draw();
// sleep
long wake = System.nanoTime() + sleep - timer.tock();
do {Thread.sleep(0);}
while (System.nanoTime() < wake);
}
} catch (InterruptedException e) {
// oh someone paused the game
}
Notes:
- For more precision, I'm using nanoseconds and a busy-waiting loop instead of just calling the
Thread.sleep()
method (it is incredibly inaccurate). My tests show that the engine can keep the desired frequency quite precisely. - I'm using a circular buffer to count the frames per second, I don't like that loop to count late ticks but I couldn't find a better way to do it.
- The
start
variable and related get methods in theGameTimer
it's just for game logic use, it isn't important for fps counting or tick/tock operations.