How can I make this simple game loop better?

I’ve been having a bit of trouble coming up with a decent game loop (or maybe this is decent, I just feel it could be better). Taken directly from the game I’m working on, my loop is below:

public void loop() {
	Date startTime = new Date();
	Date previousRepaint = startTime;
	Date currentTime = startTime;
	float delta;
	float redrawsPerSecond = 1000/maxFps;
	
	// While the game is not over...
	while(!gameOver) {
		currentTime = new Date();
		delta = currentTime.getTime()-previousRepaint.getTime();
		
		update(delta);
		repaint();
		
		previousRepaint = currentTime;
		
		// Limit repaint to the max FPS.
		if(delta <= redrawsPerSecond) {
			try { Thread.sleep(10); } catch(Exception e) { /* pass */ }
		}
	}
}

I see this as a sort of passive limitation (using Thread.sleep() instead of limiting the redraws conditionally beforehand). One thing to note is when I leverage the delta properly, I can keep CPU usage down to between 15-20% with very smooth animation.

I’m really looking for any sort of advice on this. Is there generally a better way to go about the game loop? Is this code fine, but maybe a few tweaks here and there?

are you using any libraries. cause if so. you can limit the updates in Slick. acn probably do someting similar in LWJGL and JOGL.

I’m not currently using any libraries. I’m literally just casting the Graphics object that is sent to the paint() methods I’m overriding up to a Graphics2D object and turning on anti-aliasing with the proper RenderingHints.

I will eventually switch to something a bit more powerful (and more appropriate) like Slick, LWJGL or JOGL for more complex games, but I wanted to get a good grasp of the underlying 2D rendering capabilities.

Any thoughts on the game loop itself, though?

Your loop will be jerky depending on what is going on between/during frame renders. If cpu usage stays constant, your updates will be smooth, but get a cpu usage spike and you get a jerk.

I would recommend having a variable that holds your desired frames/second and using that in combination with your delta to calculate how long you need to sleep.

This is pretty much what I use in my game loop.

	private static final int DELAYS_PER_YIELD = 1000000000;
	private static final int MAX_FRAME_SKIPS = 5;
	private static final long NANO_IN_MILLI = 1000000L;
	int fps = 60;
	long period = 1000L / (long)fps;
	boolean running = true;

	
	public void start() {
		new Thread() {
			public void run() {
				long overSleepTime = 0L;
				int noDelays = 0;
				long excess = 0L;
				Thread.currentThread().setPriority(10);
				long beforeTime = System.nanoTime();
				long lastRunTime = beforeTime;

				while (running) {
					long delta = System.nanoTime() - lastRunTime;
					lastRunTime = System.nanoTime();
					nextFrame(delta / NANO_IN_MILLI);

					render();

					long afterTime = System.nanoTime();
					long timeDiff = afterTime - beforeTime;
					long sleepTime = period - timeDiff - overSleepTime;
					if (sleepTime > 0L) {
						try {
							Thread.sleep(sleepTime / NANO_IN_MILLI, (int)(sleepTime % NANO_IN_MILLI));
						} catch (InterruptedException interruptedexception) { }
						overSleepTime = System.nanoTime() - afterTime - sleepTime;
					} else {
						excess -= sleepTime;
						overSleepTime = 0L;
						if (++noDelays >= DELAYS_PER_YIELD) {
							Thread.yield();
							noDelays = 0;
						}
					}
					beforeTime = System.nanoTime();
					int skips;
					for (skips = 0; excess > period && skips < MAX_FRAME_SKIPS; skips++) {
						excess -= period;
						nextFrame(period / NANO_IN_MILLI);
					}
					framesSkipped += skips;
				}
				System.exit(0);
			}
		}.start();
	}

Looks like a decent upgrade from my trivial game loop :slight_smile:

I’ll dissect this and see where I can get in terms of performance. Thanks for sharing your loop. Anyone else have a game loop they’d be willing to share? Preferably not based on Slick or any other game library?

I think the fps is broken, I tried setting it to very low but still keep on sucking up my cpu and rendering fast as possible.

You also in your example “framesSkipped += skips” does nothing.

boolean running - should be volatile

it also seems like an odd place to put System.exit(0)

You also might want to reset interrupt status - though it shouldn’t cause problems in this specific context, as you also rely on the running boolean and the contents of the loop should not require much time to execute.

Thread.currentThread().setPriority(10);
seems random you might want to make it relative to the calling thread or allow one to set it by exposing it with their value.

60fps uses less than 10% cpu on my machine (Dual Core 2.6GHz with 3GB RAM).
Lowering fps also lowers cpu used.

The frameSkipped is left over from stats collection, I pulled out most of the stats collection code to simplify the example and I just missed that bit.

Thanks for the input.
Where would you recommend putting the exit? When the user ends my game I set running to false which stops the loop. If I don’t call exit, the application stays open.

Why are you using Date? Isn’t a long for each timestamp enough? Use


	long startTime = System.getCurrentMillis(); //can be System.nanoTime() if you need higher precision

I dislike Thread.sleep() because it’s very unprecise on my Windows XP machine… I prefer solutions like this:


final long LOOPTIME = 1000/60; //for 60 FPS in 1000ms
long nextLoop;

while(true) {
    nextLoop = System.currentTimeMillis() + LOOPTIME;

    //do logic and repaint stuff

    while(System.currentTimeMillis() < nextLoop) {
        Thread.yield();
    }
}

That maxes the CPU on my Linux box. I think in general nanoSleep is the best solution, assuming availability of Java 1.5.

Yes, it maxes the CPU, but other Threads are able to do their work even with that. Using Thread.sleep(long ms, long ns) isn’t accurate, too, afaik.

Maybe. I found that one of the games in this year’s Java4k competition was almost unplayable until its author changed from yield to sleep, at which point it started actually detecting and handling all of my key presses.

Everyone seems to use a game loop with thread.sleep(). Except me :frowning:

What I did is basically create a repeating timer that call repaint() when it ends and I use paint() as my game loop… If the fps is faster than the Timer it will wait for the timer, if it’s slower then the next repaint() will just have to wait. Anything is wrong with that ???

I don’t even understand exactly what you’re saying, but using the Timer class is acceptable. The main problem with it is that you can’t directly control it like you can with the sleeping. So, if you’re getting slower or faster FPS you can’t really adjust it accordingly. For simple games I think it works fine, but I wouldn’t use it for anything that’s complex.

After reading it I got scare that I took a wrong way so I did some test to see how I could control the game speed so it match with the FPS. I’m still using a timer and I was able to change the game speed accordingly to the FPS. Here is a sample of my code.

public class GameFrame extends JFrame{
  
  public static int TIME_DELAY = 10;
  GamePanel gPanel;
  Timer timer = new Timer(TIME_DELAY, TimerListener);
  
  class TimerListener implements ActionListener{
    
    public void actionPerformed(ActionEvent e){
      gPanel.repaint();
    }
  }
}

public class GamePanel extens JPanel{
  
  GameFrame gameFrame;
  
  protected void paintComponent(Graphics g) {
    long time0 = System.nanotime();
    //The code of the game loop
    //....
    //end of the game loop
    long time1 = System.nanotime();
    int t10 = (int)(time1-time0)/1000000;
    int timeDelay = setTimeDelay(t10);
    //+2 because it's the average time difference between 2 repaint and
    //the time in the game loop
    gameFrame.TIME_DELAY = timeDelay + 2; 
    gameFrame.timer.setDelay(timeDelay);    
  }
  
  private int setTimeDelay(int time){
    listTimeDelay.addFirst(time);
    if(listTimeDelay.size() > 10){
      listTimeDelay.removeLast();
    }
    int retour = 0;
    for(int i=0; i<listTimeDelay.size(); i++){
      retour += listTimeDelay.get(i);
    }
    if(listTimeDelay.size() > 0){
      retour = retour/listTimeDelay.size();
    }
    //13+2 is my maximum repaint() speed
    if(retour < 13){
      retour = 13;
      //Too big value mess up with the physics
    }else if(retour > 30){
      retour = 30;
    }
    return retour;
  }
}

Anyone think it would make a problem later? Because if I have to change it I guess it’s better now than later.

That will always be a frame behind, because you’re setting the delay for the next frame based on the current frame’s fps, and you don’t appear to be using a delta variable of any kind. It won’t really be very noticeable, but I still don’t recommend using Timer.

Yay I finally made a good game loop (at least I think I do). Any places for improvement?

Check it out :

public class GameLoop implements Runnable{
    
    long desiredFPS = 60;
    long desiredDeltaLoop = (1000*1000*1000)/desiredFPS;
    
    long beginLoopTime;
    long endLoopTime;
    long currentPhysicTime;
    long lastPhysicTime;
    
    boolean running = true;
    
    public void run(){
        
        loopInitialization();
        
        while(running){
            beginLoopTime = System.nanoTime();
            executeDrawing();
            
            lastPhysicTime = currentPhysicTime;
            currentPhysicTime = System.nanoTime();
            executePhysic(currentPhysicTime - lastPhysicTime);
            
            executeLogic();
            
            endLoopTime = System.nanoTime();
            adjustSpeed();
        }
        
    }
    
    private void adjustSpeed(){
        long deltaLoop = endLoopTime - beginLoopTime;
        
        if(deltaLoop > desiredDeltaLoop){
            //Do nothing. We are alreadyLate
        }else{
            try{
                Thread.sleep((desiredDeltaLoop - deltaLoop)/(1000*1000));
            }catch(InterruptedException e){
                //Do nothing
            }
        }
    }
    
    private void loopInitialization(){
        currentPhysicTime = System.nanoTime();
    }
    
    private void executeDrawing(){
        //Do the drawing here
    }
    
    private void executePhysic(long deltaPhysic){
        //Do the physic here
    }
    
    private void executeLogic(){
        //Do the logic here
    }

You’ll be putting the garbage collector to overdrive, and hence reducing the framerate, if you try to do something like:

while(true) {

MyObject myObj = new MyObject();

}

Hmmm. I don’t really get what you are telling me. What object did I create in the loop? I can see that I create 2 or 3 long variable is it what you are talking about?

I was referring to the original post’s “currentTime = new Date();”