A good Game Loop

Hello,

For over two years I’ve been using this game loop, but now, I need delta and I just found out that this game loop delta isn’t that great.
I would like to ask you guys how to create a decent game loop with, updates happening 60 times or maybe 30 times per second and ticks once per second with delta.

Here is what I’ve been using.



	public void run() {
		// Calling the initialize Method to setup our environment
		init();
		// Variables for the FPS counter
		long lastTime = System.nanoTime();
		double ns = 1000000000.0 / 60.0;
		long lastTimer = System.currentTimeMillis();
		int frames = 0;
		int updates = 0;
		int checking = 0;
		int sum = 0;
		int avg = 0;
		double delta = 0;
		while (running) {
			long now = System.nanoTime();
			delta += (now - lastTime) / ns;
			lastTime = now;
			if (delta >= 1) {
				// 60 times per second this is reached
				update(this.public_delta);
				updates++;
				delta--;
			}
			// Render as many times as u can
			render();
			frames++;
			Display.update();
			if (System.currentTimeMillis() - lastTimer > 1000) {
				lastTimer += 1000;
				// Once per second this is reached
				this.public_delta = delta;
				this.public_fps = frames;
				String title = GeneralSettings.fullname + " FPS: " + frames + " UPS: " + updates/* + " Delta: " + this.getDelta() */;
				if (GeneralSettings.useAverageFPS) title += " Average: " + avg;
				if (GeneralSettings.showLightFloat) {
					if (world != null) title += " Light: " + world.DAY_LIGHT;
				}
				Display.setTitle(title);
				if (GeneralSettings.useAverageFPS) {
					sum += frames;
					checking++;
					if (checking == GeneralSettings.ticksPerAverage) {
						avg = (sum / checking);
						checking = 0;
						sum = 0;
					}
				}
				tick();
				updates = 0;
				frames = 0;
			}
			if (Display.isCloseRequested()) running = false;
			Display.sync(fps_lock);
		}
		// If the game is closed, cleanup!
		cleanup();
	}

The problem with my game loop is, if I lock the fps at 30 for example, the UPS will also be lock at 30.
Also my Delta sometimes is like 0.03 others like 500.0. It reaches very high numbers when the computer cannot reach the 60 UPS per second.

How could I fix this?

Thanks
Joaogl.

I use a fixed time-step game loop with interpolation. The update function takes the time of a single frame ([icode]second/targetUPS[/icode]) and the render function takes the interpolation as the argument. The overall loop looks like this.

The above looks a lot simplified, but it isn’t. The complexity here is in how to limit the UPS aka the logic rate, but keep on rendering as many frames as you can. This is how the code looks like.


public void start()
{
    // Initialize the Game
    init();

    // GameLoop constants
    final double second = TimeUtils.convert(1, TimeUtils.Unit.SECONDS, TimeUtils.getDefaultTimeUnit());
    final double frameTime = second / targetUPS;
    final double maxFrameSkips = 10;

    double currentTime;
    double previousTime;
    double elapsed;

    double lag = 0;

    double lastUPSUpdate = 0;
    double lastFPSUpdate = 0;

    int updatesProcessed = 0;
    int framesProcessed = 0;
    int skippedFrames = 0;

    previousTime = TimeUtils.currentTime();

    running = true;

    // The Game Loop
    while (true)
    {
        if (Display.isCloseRequested() || !isRunning())
        {
            Game.end();
            break;
        }

        currentTime = TimeUtils.currentTime();
        elapsed = currentTime - previousTime;

        lag += elapsed;

        // The update loop, update constantly to meet the target UPS while skipping frames
        while (lag > frameTime && skippedFrames < maxFrameSkips)
        {
            update((float) frameTime);
            gameState.update((float) frameTime);

            lag -= frameTime;
            skippedFrames++;

            // Calculate the UPS counters
            updatesProcessed++;

            if (currentTime - lastUPSUpdate >= second)
            {
                ups = updatesProcessed;
                updatesProcessed = 0;
                lastUPSUpdate = currentTime;
            }
        }

        // The simplest way to calculate the interpolation
        float lagOffset = (float) (lag / frameTime);

        render(lagOffset, batcher);
        gameState.render(lagOffset, batcher);

        // Calculate the FPS counters
        framesProcessed++;

        if (currentTime - lastFPSUpdate >= second)
        {
            fps = framesProcessed;
            framesProcessed = 0;
            lastFPSUpdate = currentTime;
        }

        // Swap the buffers and update the game
        Display.update();

        skippedFrames = 0;
        previousTime = currentTime;
    }

    Game.end();
}

This is how I do in my engine. The actual game loop looks a lot complicated when added null checks for the game states and when I run the InputEngine at a more faster rate, but is more or less the same. If I disable the VSync and lock the logic rate at 60, this loop does me 60-61 UPS and 1700-2300 FPS.

Hope this helps.

First of all, thank you very very much!

Second, whats your TimeUtils.currentTime();?

I’ve tried both System.nanoTime and System.currentTimeMillis and it didnt work that well.

That is a function that returns the current time in seconds. Here is the complete class for you.

https://github.com/sriharshachilakapati/SilenceEngine/blob/master/src/main/java/com/shc/silenceengine/utils/TimeUtils.java

I was reading your diagram and your code and I have a doubt.

“While (lag > frameTime)” - This is to fix the timestep? in libGDX using Box2D is really easy to fix timestep, but I’m trying a few days solve the timestep problem programatically without Box2D.

You’re right, the inner loop is the logic loop. It plays catch up by skipping some frames if the lag is increased. But at the same time, there is a maximum frameskip to ensure that a frame is rendered at least after ten logic cycles. This ensures that the game runs consistent on both high end systems as well as the low end ones.