Timing in main loops

The main problem is to make the movement in the game to appear smooth and responsive. Additionally one often don't want the game to use 100% of the CPU power (at least not for non fullscreen games).

There are a few different solutions:

Ignore the problem

One can simply just update the logic, draw graphics and possibly sleep for a fixed time or yield, and start over again. This will make the game run differently on different hardware or even with different load on same hardware. This should only be done for prototyping if even then.

  • Pro
    • Extremely quick and simple to implement
  • Con
    • Very unreliable

Fixed framerate

Try to display a fixed number of frames per second (FPS). Frame then means that the game will read inputs, update game state (logic) and (re)draw the screen. Each frame has a certain amount of time in which it has to complete its tasks, and then sleep for the time left till next frame update.

  • Pro
    • Quite simple to implement
    • Game logic is trivial, since each tick (time between updates) is fixed
  • Con
    • Have to spec for worst case scenario. High end rigs won't be utilized.
    • If each game-loop isn't completed in time, the game will slow down or will have to drop renering to catch up

Call for help: Code example

public class BasicTimer {
	private int fps;
	private long timeThen;
	boolean newVersion = true;
	public BasicTimer(int frameRate) {
		if (System.getProperty("java.version").startsWith("1.4"))
			newVersion = false;
		if (newVersion) {
			fps = frameRate;
			timeThen = System.nanoTime();
		} else {
			fps = frameRate;
			System.out.println("Old Version Detected: " +
				"Running Old Java Timer Version");
			timeThen = System.currentTimeMillis();
		}
	}
	public void sync() {
		if (newVersion) {
			long gapTo = 1000000000L / fps + timeThen;
			long timeNow = System.nanoTime();
				
			while (gapTo > timeNow) {
				try { Thread.sleep(1);
				} catch (InterruptedException e) {}
				timeNow = System.nanoTime();
			}
			
			timeThen = timeNow;
		} else {
			long gapTo = 1000 / fps + timeThen;
			long timeNow = System.currentTimeMillis();
				
			while (gapTo > timeNow) {
				try { Thread.sleep(1);
				} catch (InterruptedException e) {}
				timeNow = System.currentTimeMillis();
			}
			
			timeThen = timeNow;
		}
	}
	
	
	public static void main(String args[]) {
		System.out.println("Simple Timer Test: set to 2" +
				"(should actually be 60 for most games)");
		BasicTimer timer = new BasicTimer(2);
		while (true) {
			timer.sync();
			System.out.println("TICK");
		}
		
	}
}

Dynamic framerate

A game loop (logic and drawing) is executed as fast as possible. Then the thread yields or sleeps for a short time, and the next loop starts. Each loop keeps track of how long time has passed since last loop (tick). Each update will then have to be made in regards to the tick. Example: Say a player is moving at 50 pixels/sec. If the tick is 1/50 second, then is should be moved 50*1/50=1 pixel. However if the player should slow down with 5%/sec and 5 pixels/sec, then the calculations become very complex.

  • Pro
    • Can utilize the hardware better
    • Can to some degree adjust for short time loads on the hardware
  • Con
    • Can lead to very complex logic
    • Not completely deterministic (might play slightly different on different hardware).

Call for help: Code example

public abstract class GameLoop implements Runnable {
	
	private long desiredFPS = 60;
        private long desiredDeltaLoop = (1000*1000*1000)/desiredFPS;
    
	boolean running = true;
	
	public void run(){
		
		long beginLoopTime;
		long endLoopTime;
		long currentUpdateTime = System.nanoTime();
		long lastUpdateTime;
		long deltaLoop;
		
		while(running){
			beginLoopTime = System.nanoTime();
			
			render();
			
			lastUpdateTime = currentUpdateTime;
			currentUpdateTime = System.nanoTime();
			update((int) ((currentUpdateTime - lastUpdateTime)/(1000*1000)));
			
			endLoopTime = System.nanoTime();
			deltaLoop = endLoopTime - beginLoopTime;
	        
	                if(deltaLoop > desiredDeltaLoop){
	                      //Do nothing. We are already late
	                }else{
	                     try{
	                          Thread.sleep((desiredDeltaLoop - deltaLoop)/(1000*1000));
	                     }catch(InterruptedException e){
	                          //Do nothing
	                     }
	                }
		}
	}
	
	protected abstract void render();
	
	protected abstract void update(int deltaTime);

}

Separated threads for graphics and logic

In order to avoid the the complexity with the Dynamic framerate and still utilize the hardware and create smooth movement, one can split up the logic and the rendering into two different threads. The logic loop is the same as the fixed framerate, and the graphics is updated at dynamic (and typically higher) framerate. The rendering will then have to interpolate between values in two different gameloops.

  • Pro
    • Easier game logic
    • Deterministic game
    • Smooth graphics
  • Con
    • More complex rendering logic
    • Multithreaded, thus increasing complexity
    • The graphics will lag ~1 frame (typically negligible)

Call for help: Code example


Links

Fast engine.tick() design

JGO tutorial

Detailed "Separated threads for graphics and logic" article called fix-your-timestep

More extensive talk about different types of gameloops at koonsolo