Skip to main content
gamedev.net
🔒 Locked 🎮 Unity

[java] Different speeds at every run?

Started by rogierpennink Jul 1, 2007 at 5:16 AM 3 replies 1.1k views
Original Post
rogierpennink
rogierpennink
Hey everyone, I recently started on a small snake game in java and so far everything is coming along fine. Everything, except for this very odd phenomenon that keeps occurring more often than not when running the application. I use System.nanoTime() for the timing in my application and every tenth of a second I update the movement of my snake. According to my calculations, everytime when 'timeElapsed' reaches 10^8 nanoseconds I should update. Sometimes this yields the intended results, but like I said, more often than not it doesn't yield the intended results. At these times the movement of the snake will be twice as slow. I have also included a small explosion animation for when the snake hits the walls or itself and this animation takes twice as long as well. This is easily measurable since I have specified the animation to run for 1500 milliseconds and whenever the application is in it's 'slow mode' it takes around 3 seconds to complete. As of yet I have discovered no means of influencing the speed at which the application updates the snake movement and animation other than running multiple instances of the application at the same time. The first instance will have a slow snake and a slow animation, the second instance (leaving the first one open) will have small 'speedups' where the update-speed will sometimes go to normal for a small time and then return to being slow. At around the third instance and more the update speed will be entirely normal for both the snake and the animation. I find this pretty odd... Since this will probably sound very vague I have uploaded a .jar with the game as it currently is. You can download it from http://www.digillusions.com/Snake.jar. Since I suspect this to be some sort of timing problem I'll quickly explain the game loop and method of updating I use. Basically I use a somewhat modified version of the GamePanel class that is introduced in "Killer game programming in Java" by Andrew Davison. When the application starts, it creates a new thread in which to run the game loop. Thus, the 'run' method looks like this:

while ( running )
{					
	/* Get the current time. */
	before = System.nanoTime();
			
	/* First update the game state. */
	update( diff + ( ( sleeptime > 0 ) ? sleeptime : 0 ) );
			
	/* Then do the painting. */
	paint();
			
	/* Flip buffers. */
	flip();
			
	/* Get the current time and calculate time difference between last and current frame. */
	after = System.nanoTime();
	diff = after - before;
	sleeptime = ( (long)( 1000.0 / targetFPS ) * 1000000L ) - diff;
	framecount++;
			
	/* Update the FPS. */
	elapsedtime += diff + ( ( sleeptime > 0 ) ? sleeptime : 0 );
	if ( elapsedtime >= 1E9 )	/* If one second passed. */
	{
	        actualFPS = framecount;
		elapsedtime = 0L;
		framecount = 0;
	}
			
	/* Attempt to sleep a little bit, if we don't manage to get some sleeptime once in a while
	 * we'll yield after that happened 16 times. */
	if ( sleeptime > 0 )
	{
		try
		{
			Thread.sleep( sleeptime / 1000000L ); /* Nanoseconds to Milliseconds. */
		}
		catch ( Exception e )
		{
			e.printStackTrace();
		}
	}
	else
	{
		if ( ++nodelays >= 16 )
		{
			Thread.yield();
			nodelays = 0;
		}
	}			
}

I am subclassing GamePanel and overriding the update and paint methods for each specific application, and the update method for this snake game looks like:

protected void update( long timedelta )
{
	timeElapsed += timedelta;
				
	if ( timeElapsed >= 1E8 )
	{		
		/* Update the level. */
		level.update();
		timeElapsed = 0L;
		
		if ( !level.willDie() )
		{
			level.getSnake().move();				
		}
		else
		{
			if ( !explosion.isRunning() ) explosion.startAnimation( false );
			state = GameState.GAME_LOST;
		}
	}
		
	if ( state == GameState.GAME_LOST )
		explosion.update( (int)(timedelta / 1000000) );
}

As you can see, every tenth of a second the game is 'updated' but judging by the observable behaviour of the application a tenth of a second is a very relative amount of time... I hope I have provided enough information on the problem, if not I'll be happy to provide more. Regards, Rogier Pennink
ToohrVyk
ToohrVyk
By using timeElapsed = 0L; you lose any nanoseconds in excess of 1E8: if 2E8 has elapsed, you'd still only update once.

The correct code is:
while (timeElapsed > 1E8) {  // Do things  timeElapsed -= 1E8;}
rogierpennink
rogierpennink
Thanks, that makes sense and I changed it immediately. Unfortunately, it doesn't solve the problem with the speed being twice as slow as it should be most of the time. Since the updating seems to be OK other than this glitch I'm at a loss of what else could cause the problem.
FlaiseSaffron
FlaiseSaffron
The method Thread.sleep(int), is causing you precision problems. Calling that method delegates the delay to the OS thread scheduler, and under Windows the smallest update is 15 milliseconds, so you're missing frames.
I suggest you write your own sleep method that repeatedly checks the system nanotime and calls Thread.yield().


Also, it would be helpful to people who review your code like this if you factored your literals into constants, for example 1000000L would be MILLIS_TO_NANOS.
rogierpennink
rogierpennink
Thanks for your reply, and more importantly, the suggestion that it contained. I have not exactly followed your advice (implementing my own sleep method), but instead I turned a few pages in "Killer Game Programming in Java" and noticed, to my horror, that the author had already foreseen this problem and solved it by measuring the time the application actually slept and detracting that from the next sleeptime. Right now, every run of the application seems to be at normal speed so I'm slowly getting my hopes up.
In any case, you pointed the problem out for me, so I thank (and rate) you for that!

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.