5
\$\begingroup\$

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:

  1. 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.
  2. 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.
  3. The start variable and related get methods in the GameTimer it's just for game logic use, it isn't important for fps counting or tick/tock operations.
\$\endgroup\$
3
  • \$\begingroup\$ Welcome to Code Review! Your post is on a good track but is still missing something vital: you haven't explained what your code does. What is this game? How does it work? We need more information. \$\endgroup\$
    – SirPython
    Commented Mar 11, 2016 at 23:38
  • \$\begingroup\$ Thank you @SirPython! My code is pretty abstract at this moment, imagine it as a framework for developing any kind of 2D game! An abstract engine that does the hard work. I've already developed a basic game-test on my engine but it's pretty basic stuff: some colored squares that moves around the window :) \$\endgroup\$
    – Oneiros
    Commented Mar 12, 2016 at 12:26
  • \$\begingroup\$ That sounds pretty cool! Now, if you could, somehow rewrite that explanation somewhere in the post so future reviewers can find it more easily. \$\endgroup\$
    – SirPython
    Commented Mar 12, 2016 at 12:50

1 Answer 1

1
\$\begingroup\$

The whole tick tock mechanism is not needed for your main loop.

You've set up this elaborate contraption (it took me a while to understand) which measures how long your last "frame" took. Then, when deciding on how long you'll need to wait to get to the next frame, you retrieve that time, and subtract that from the current time plus how long you want to wait.

All this is a very elaborate mechanism for this:

long sleep = (long) (GameTimer.ONE_SECOND / desiredFPS);
try {
    while(true){

        // tick and print fps
        long lastTick = System.nanoTime();
        timer.tick();
        System.out.println(timer.getFPS());

        // input, update and draw (abstract methods of my engine class)
        input();
        update();
        draw();

        // sleep
        long wake = lastTick + sleep;
        do {Thread.sleep(0);}
        while (System.nanoTime() < wake);
    }
} catch (InterruptedException e) {
    // oh someone paused the game
}

This rewrite doesn't really help so I'll explain:

What you have made is something that keeps track of ticks. That's okay. But to then use the tick timer in the calculation makes no sense - you already HAVE the time you started the tick - it's when you entered the loop!

Your GameTimer is useful for doing things like showing debug information in graph form, or finding patterns in lagspikes. But for this usecase, just a single long will do.

And first and last are wrongly named. It's not a pointer to the first and last item in the circular buffer, it's a pointer to the first and last frame of the past second. This should be encoded in the variable name.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.