Game Timer

Hi, i´ve got a problem with the timemanagement in my Game.
I searched a lot in these forums, but didn´t get the right idea of
how to manage that my sleep(32) really does sleep exactly 32 ms.
I don´t want to get new stuff for this, just Java 6.0 Update3 and nothing else
because some other people might want to play the game, too, but only
want to install simply Java.

So i hope someone can help me with this ???
Thanks

I’ve used this one for years:


   public static final void sleep(long ms)
   {
      sleep(ms, true);
   }

   public static final void sleep(long ms, boolean consumeInterrupts)
   {
      final long end = (System.nanoTime()/1000000L) + ms;

      while ((System.nanoTime()/1000000L) < end)
      {
         try
         {
            long togo = end - (System.nanoTime()/1000000L);

            // ensure we don't suffer from OS 'sleep-snapping'
            long sleep = togo / 2 + 1;

            if (sleep > 0)
               Thread.sleep(sleep);
         }
         catch (InterruptedException exc)
         {
            if (consumeInterrupts)
            {
               Thread.currentThread().interrupt();
               Thread.interrupted();
            }
            else
            {
               return;
            }
         }
      }
   }

Sorry, in my App. it didn´t help, either way (my old way, or your way )
my max. FPS is now 38.
But it depends on my sleepSetting.
If i say sleep(1);
i get 38 FPS and it sleeps for like 26 ms., not my desired 1 ms, which might indeed be
impossible i guess.
But if i say sleep(32); , which should be possible,
i only get 14 FPS and ist sleeps for like 71 ms.
Why is that?
Here´s the code (i have an ownClass for my Thread for some reasons like FPS-tests):

package Tools.Helpers;

import java.awt.Toolkit;

/*

  • Created on 27.05.2007
    */

public class Threadder extends Thread {
/*
----------------------------------------------
--------------{Description}--------------
----------------------------------------------

 */
//	##################################################################################################
//	#######################   ATTRIBUTE      ATTRIBUTE      ATTRIBUTE   ##############################
//	##################################################################################################

//	+++++++++++++++++++++++++++++//
/*	---[ Thread ]---*/
//	+++++++++++++++++++++++++++++//
public long SLEEP = 200;
long SLEEP_Backup;
boolean THREADACTIVE = true;
boolean isActive = true;

//	+++++++++++++++++++++++++++++//
/*	---[ Listener ]---*/
//	+++++++++++++++++++++++++++++//
//---[ Listener, who takes Updates ]---*/
ThreadderListener listener;


//	##################################################################################################
//	#####################   KONSTRUKTOR   ##########################
//	##################################################################################################

/*||Created on 25.07.2007||*/
public Threadder(ThreadderListener newListener,int sleep) {
	super();
	listener = newListener;
	SLEEP = sleep;
	SLEEP_Backup = SLEEP;
	start();
}

//	##################################################################################################
//	##########################   METHODS    ##############################
//	##################################################################################################

public void run() {
	while(THREADACTIVE){
		//:::[ does actions, like repaint etc. ]::://
		listener.updateTime(1);
		if(isActive){
			listener.redoActions();
		}
		try {
			sleep(SLEEP);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		listener.updateTime(2);
	}
}

//	==========================================================================
/*	===[  ]===	*/
//	==========================================================================	
public void disableMe() {
	/*||Created on 31.05.2007||*/
	SLEEP_Backup = SLEEP;
	isActive = false;
	SLEEP = 1000;
}

//	==========================================================================
/*	===[ Threadder reset ]===	*/
//	==========================================================================	
public void activate() {
	/*||Created on 06.08.2007||*/
	SLEEP = SLEEP_Backup;
	isActive = true;
}


//	##################################################################################################
//	##################################################################################################
//	##################################################################################################

}

The computer timer always has a certain granularity. I use the millisecond timer (System.currentTimeMillis), and it has a 10-ms granularity on Windows XP, meaning that you always sleep for multiples of 10 ms. On Linux and Mac, I believe the granularity is 1 ms.

When you use the sleep method you’re using, it uses the millisecond timer. There is a sleep method that uses milliseconds AND nanoseconds, but the real problem is that you’re always sleeping the same amount of time. What you need to do is sleep for the amount of time that’s left in the frame. Some of the time is already used up by the time you spend drawing and updating. My own main loop code looks like this:

package cg.puzzlecarnival;
import cg.main.Time;
import cg.puzzlecarnival.gui.GuiAccess;

/**This class executes the main loop.
 * @author Steven Fletcher
 * @since 2007/08/14
 * @version 2008/02/21
 */
public class MainLoop {
/**Executes the game's main loop.*/
public static void execute() {
	//This variable is used to only skip yielding a certain number of times in a row.
	byte numDelays = 0;
	
	//This variable stores how much time the loop overslept by in the last cycle.
	//Negative values probably won't occur because Thread.sleep shouldn't undersleep.
	long overSleepTime = 0L;
	
	//This variable is used for computing the length of an update phase.
	long lastUpdatePhase = Time.currentTimeMillis();

	while(true) {
		//if the application isn't visible, sleep for half a second
		if(!GuiAccess.isApplicationActive()) {
			try {
				Thread.sleep(500);
			} catch(InterruptedException exception) {}
				
			continue;
		} //end if the frame isn't visible
		
		//figure out the start of the current phase
		long currentCycle = Time.currentTimeMillis();
		long updatePhaseLength = currentCycle - lastUpdatePhase;
		if(updatePhaseLength > period)
			updatePhaseLength = period;
		
		//update the current model
		GuiAccess.updateLogic(period);
		lastUpdatePhase = Time.currentTimeMillis();
	
		//render the game
		GuiAccess.showFrame();
	
		//figure out how long the cycle took
		long timeAfterCycle = Time.currentTimeMillis();
		long cycleLength = timeAfterCycle - currentCycle;
		long sleepTime = period - cycleLength - overSleepTime;
		
		//if some time is left in this cycle
		if(sleepTime > 0) {
			//sleep
			try {
				Thread.sleep(sleepTime);
			} catch(InterruptedException exception) {}
			
			overSleepTime = Time.currentTimeMillis() - timeAfterCycle - sleepTime;
		} //end if some time is left in this cycle
		//else no time is left in this cycle
		else {
			overSleepTime = 0L;
			
			//don't sleep, but yield if absolutely necessary
			numDelays++;
			if(numDelays >= maximumDelaysPerYield) {
				//yield to let other threads execute
				Thread.yield();
				numDelays = 0;
			} //end if there have been too many delays
		} //end else no time is left in this cycle
} //end while forever
} //end execute

//PRIVATE CONSTANTS//////////////////////////////////////////////////////////////////////
//the maximum number of consecutive cycles that can skip the yield
private static final int maximumDelaysPerYield = 16;

//private static final int maximumMillisecondsPerUpdate = 40;
//private static final int millisecondsPerFrameRedraw = 10;

//1000/period frames per second
private static final int period = 40;
} //end class MainLoop

The call to the Time method just calls System.currentTimeMillis. GuiAccess is the class my paint and update methods are in.

As an aside, I wouldn’t suggest switching to System.nanotime. That particularly timer doesn’t work reliably on processors with energy saving capabilities (which is common, especially on laptops) and older dual core AMD processors.

using Swing Timer’s does simplify the way your frame rate varies, because even though a process cycle can take much more time than the initial delay, Swing will coalesce the pending cycles in one single cycle and wait for it to finish. :slight_smile:
But as told above in the prev post, a good timer is always more accurate when the timing resolution is well managed with System times, as nanos are at higher resolutions better than millis. But higher resolution (i.e. smaller delays) are rather realized for the Animation framework. :wink:

Hi again.
I need to thank you a lot. This one did the job :slight_smile:
My testframe runs almost constantly with 24-25 FPS like I want it.
With your way of solving this problem I can also run it at 50 FPS constantly
but I guess 25 is enough as the human eye sees less :wink:

I hear that thing about 25fps for the human eye so often, but it’s just not true.

I can clearly see the difference between 60 and 80fps. (on a TFT monitor)

I think that´s based on the animation/games you look at.
60/80 FPS doesn´t mean every function in the game etc.
runs at 60/80 FPS.
For example, you need to refresh walk-cycles much more than
some effect like raind or a tilebased animation.
So the difference you see between 60 and 80 FPS is what was intended
to be seen different I guess.
Please correct me if I´m wrong, not so long in the business, but that´s what
I explored when playing different games and programming effects like mentioned before.