Game Loop variations

I have a simple question. It’s about basic game loop. When I’ve written my apps, I used a loop like this:

while (true)
{
	int delta = (int) (System.currentTimeMillis() - lastLoopTime);
	logic(delta);
	lastLoopTime = System.currentTimeMillis();
	
	draw((Graphics2D) strategy.getDrawGraphics());
	
	strategy.show();
        // Calculate sleep time
        try { Thread.sleep (sleepTime);}catch(Exception e) {}
}

recently i started looking at others’ people sources and I’ve found loops like this:
(source taken from http://www.cokeandcode.com/games/4k/city4k/R.java)

while (true)
{
	int delta = (int) (System.currentTimeMillis() - lastLoopTime);
	for (int i=0;i<delta/10;i++) {
		logic(10);
	}
	logic(delta % 10);
	
	lastLoopTime = System.currentTimeMillis();
	
	draw((Graphics2D) strategy.getDrawGraphics());
	
	strategy.show();
}

Could you please explain me the reason, why is it better to break logic into 10 millisecond calls plus one delta % 10 call?
Second point is: code below never sleeps. I thought it is good idea to call Thread.sleep from a game loop to give some time to other threads. Actually this code is from 4k contest so this might be the reason.

In other pieces of code I’ve seen Thread.yield() instead of Thread.sleep(). Which approach is preferable?

I personally use the following:

while (playing) {
	updateGameState();
	renderScene();
	waitForSynchronization();
}

It works by having a high priority thread that does nothing but awake a synchronization thread 60 times a second. waitForSynchronization will enter the synchronization thread and call wait(), it’s a really good way to handle the game loop.

In fact it works so well that I have modelled my game engine like the gameboy advance hardware (with the same registers etc), so if you unroll what happens this is what you get:

  • updateGameState called
  • renderScene called (prepares tiles for the graphics engine)
  • waitForSynchronization called
  • synchronization threads awakened
  • graphics engine renders screen
  • <<< loop

The synchronization allows you to make a simple call similar to what would typically be used in a game (waitVBL()).

Hmm, interesting. I have some questions about your approach.

You actually call updateGameState(deltaMills) not just updateGameState()?
“renderScene” is the same action as “graphics engine renders screen” or not?
waitForSynchronization(); - just waits for other thread to call “notify” on some object?

Can you explain why your solution is better than the game threads from initial post?

PS Sorry for so much questions, but your approach is rather interesting and I’m just curious about details.

No need to send the frame time, you update the game state irrespective of the time and assume that you are running at a constant frame rate. You can [of course] track when you’ve taken too long and adjust the physics to take account of that time, but you probably would rather change the framerate completely for the game based on an a benchmark of the hardware (if your game is more CPU intensive).

renderScene is not the same as the graphics engine rendering the screen, it is when you are [say] setting the tiles for the tetris block, when the graphics engine renders the screen it is plotting the pixels of each of the tiles with its layer effects, rotation and zoom.

Yes, waitForSynchronization() does just wait for another thread to call notify on an object. I find it better as it allows me to use the same approach you would use when developing for a console. It gives you a simple implementation with full synchronization for consistent frame rates with much more readable code. Plus any beginner can understand it!

Thanks for the reply. I’ll try to implement your technique.
Still I’m wondering about the questions in the initial post:

why is it better to break logic into several relatively small calls?
should I sleep or yield in my game loop?

In the method I gave you need not yield or sleep, just wait. Here are two examples that are probably the same!

// method 1
package javaThreadSynchronization;

public class WaitVBLSynchronization implements Runnable {
	public boolean running = true; 
	public Object waitingObject=null;
	public static void main ( String argv [] ) throws InterruptedException {
		WaitVBLSynchronization sync = new WaitVBLSynchronization();
		for ( int i = 0; i < 6; i ++ ) {
			sync.waitVBL();
			System.out.println(i);
		}
		sync.running = false;
	}
	public WaitVBLSynchronization (){
		Thread t = new Thread(this);
		t.start();
		
		// this high priority is valid because of how little the thread does
		t.setPriority(Thread.MAX_PRIORITY);
	}
	
	public void waitVBL () throws InterruptedException{
		waitingObject =  new Object();
		synchronized ( waitingObject ) {
			
			waitingObject.wait();
			waitingObject = null;
		}
	}
	
	public void run() {
		while ( running ){
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) { }
			
			if ( waitingObject != null ) {
				synchronized (waitingObject){
					waitingObject.notify();
				}
			}
		}
	}
	
}
// method 2
package javaThreadSynchronization;

/**
 * Will test synchronization involving one thread synchronizing
 * itself wake another thread once every 60th of a second
 * @author Keldon
 *
 */
public class VBLScreenSynchronizationTest {
	public static void main ( String argv [] ) throws InterruptedException {
		Runnable runnable = new Runnable(){
			public void run() {
				int counter = 0;
				int seconds = 0;
				while (true){
					if ( counter == 0){
						counter = 60;
						System.out.println((seconds++) + " seconds has passed");
					}
					counter--;
					try {
						synchronized (this){
							wait();							
						}
					} catch (InterruptedException e) {
						System.err.println("wait failed");
						System.exit(0);
					}
				}
			}
		};
		Thread currentThread = new Thread(runnable);
		currentThread.start();
		VBLSynchronization sync = new VBLSynchronization(runnable);
		sync.begin();
	}
	
	private static class VBLSynchronization implements Runnable {
		Object object;
		public VBLSynchronization (Object o ){
			this.object = o;
		}
		
		public void begin (){
			new Thread(this).start();
		}
		
		public void run() {
			while (true){
				try {
					Thread.sleep(1000/60);
					synchronized (object){
						object.notify();						
					}
				} catch (InterruptedException e) {
					System.err.println("Thread sleeping failed");
					System.exit(0);
				}
			}
		}
	}
}

By the way, it may be easier to synchronize on current Object instead of creating a single object monitor. See:

public synchronized void waitForURL() {
        try{ wait(); } catch(InterruptedException e) { e.printStackTrace(); }
}

:smiley:

lol; oh yeah! Maybe there was some profound reasoning behind the decision; it might be because I was at one time maintaining the HBL interrupts with threads until I felt it would be too much of an overhead waiting and notifying a single thread for every horizontal line in each frame.

Looking at it it makes sense to synchronize the entire object, thanks for pointing that out.

that sounds good… good luck!

There are two basic approaches in controlling the gameloop speed

  1. Use a fixed framerate (for example 60 fps)
  2. Go “flat out” or with fixed small sleep and calculate all movement based on the deltaTicks between frameloops (fast machines could for example run at 100fps and slow at 40)

1 is what Keldon described. (Using synchronization or more commonly calculate sleep so that each game loop takes the same time)
Pro:
The game always plays the same
Easy to program

Con:
Faster computers will not be utilized fully
Game will not be playable at all/behave differently on computers that not quite can produce the fixed framerate.

  1. AAA games will typically use this and many hobby games as well
    Pro:
    Utilized the power of the machines very well.

Con:
Game might behave slightly different on computers with different performance
A bit more complex to code

What you saw in the 4K code was a clever way to try to get the game to always play the same at the same time as the computer is utilized to the max.
Con:
A slight performance hit (if the logic part takes a relevant time compared to the draw task), since logic is executed several times per loop instead of one.
The game loop is still tick based so the logic is still a bit more complex than fixed framerate.
Behavior will not be 100% identical on different computers, just more similar.

I hope it is possible to understand my brief explanation and that I haven’t said anything completely wrong :stuck_out_tongue:

I beg to differ; every game on the GBA, SNES and NES would have used one like what I gave. In fact this is why 60hz NTSC games play faster than their 50hz (UK) PAL systems. On the PC it would be a different story where you have the varying frame rates, etc. Another pro/con is to do with consistency of calculations; for example if your replay code works by tracking the user input each frame then you will have to recalculate with the frame difference.

And for some games you don’t want varying frame rates, take Tetris for example; it’s a simple game so there is no benefit from a faster computer. AAA titles tend to have a minimum frame-rate, and just play games slower! You can only really utilize CPU power with more detailed graphics and effects, any utilization affecting gameplay will essentially mean that your PC determines what game you are playing :slight_smile:

When you are animating with bitmaps and not tweened vectors and polygons then assuming a fixed frame rate is easier for collision since you are not able to utilize frame independent collisions. Now don’t get me wrong, I’m not suggesting not to use variable frame rates (because I use them too), but know reasons why - but more importantly how.

Having said that my method requires only one minor change, which is to pass the time taken for the frame!

In my game engine, the FPS is default limited to the screen refresh rate. The user of the engine can then decide to either remove all limits (which will just let the game loop call a Thread.yield() without sleeping) or set a fixed limit. All game objects speeds etc. are set in pixels/second, as opposed to pixels/step