Smooth animation with pure java?

Hi! I’m trying to do smooth (not choppy) animation, but all the timers I tried (Timer.sleep, LockSupport.parkNanos) have too much jitter, or maybe something else, but the animation simply isn’t smooth. I’m using bufferstrategy and have 300-400 fps without FPS limit.
The only good timing is this (nearly busy wait, because it has high cpu load):
while( System.nanoTime()-timeout < (1000.0/60.0)*1000000)
Thread.yield();

I even tryied wait for 10ms and then busy wait, but this is also choppy.
I want the game to be playable from web page (applet), so I want to use only pure java (java2d) because of security dialogs. Is there a good solution which doesn’t load cpu?

post more code plz, with 400 fps you animation should be smooth with any timer

No, I want to limit it to 60fps and then it’s choppy. I’ll post it tomorrow, because now I have some experimental bunch of code with meaningless variable names… It’s choppy in the same way as pulpcore pathmotion sample.

ok, if the animation look “chopy” it cannot come from a single wrong frame, you probalby have problem on your main algo, that’s why I ask to see more

Windows, right?

Before your main loop, start off a daemon thread that does Thread.sleep(Long.MAX_VALUE);

Something like:


Thread thread = new Thread(new Runnable() {
  public void run() {
    try {
      Thread.sleep(Long.MAX_VALUE);
    } catch (Exception e) {
    }
  }
});
thread.setDaemon(true);
thread.start();

Having a sleeping thread forces the VM to use the high-precision timer. The daemon bit isn’t necessary, but saves you from having to remember to kill the thread on exit.

[quote]Having a sleeping thread forces the VM to use the high-precision timer
[/quote]
good idea but really I am not sure that having a timer precise to a NS will change anything to the smoothness of the animation, if you get something approximatly precise up to 10/20 ms you should get smooth animation, I beilieve OP have another problme than the timer precision

good idea but really I am not sure that having a timer precise to a NS will change anything to the smoothness of the animation, if you get something approximatly precise up to 10/20 ms you chould get smooth animation, I beilieve OP have another problme than the timer precision
[/quote]
The system timer is randomly off by >10 ms, though. So doing a sleep(10) can easily result in sleeping for 20+ms. You end up skipping frames a couple of times a second, and it’s definitely very noticeable.

The system timer is randomly off by >10 ms, though. So doing a sleep(10) can easily result in sleeping for 20+ms. You end up skipping frames a couple of times a second, and it’s definitely very noticeable.
[/quote]
sleeping is not what I was thinking about, skipping one frame will not make an animation looking “choppy” (sorry to quote this word but to be true I dont know it :slight_smile: but I guess)

you can get smart animation using currentTimeMillis using something like :
while(notTimeTorender) Sleep(1) ;

not sure but I remember to have told about that in another post, basically neither do Sleep(someTime) always while(something) sleep(1)

NB: System.currentMillis is very (maybe the most ?) accurate on the long term

I guess it depends on what you mean by choppy. Skipping a frame every second or thereabouts will definitely not look smooth, though.

That does help a bit, but not enough to really solve the problem. This is just from my personal experience in trying to track this issue in my own code. Having a perma-sleeping thread does, though (and I’ve seen others mention this as well).

Btw, fun fact - the timer’s precision is also affected by other apps you have running. For example, if you have Chrome running and are logged into gmail, the timer precision will be much better, though still not great. It just depends on if the other apps are telling the OS to use high precision or not, and when.

[quote]Btw, fun fact - the timer’s precision is also affected by other apps you have running. For example, if you have Chrome running and are logged into gmail, the timer precision will be much better, though still not great. It just depends on if the other apps are telling the OS to use high precision or not, and when.
[/quote]
hehe I know I know :wink: http://www.java-gaming.org/index.php/topic,22933.msg189842.html#msg189842

it is based in CPU consumption that’s why it is requiered to do while(something) sleep(1) and never sleep(somethng)

[quote]I guess it depends on what you mean by choppy. Skipping a frame every second or thereabouts will definitely not look smooth, though.
[/quote]
with 60 FPS this wont affect user experience

It’s more or less 1-2 jitters/s. Look at that pathmotion sample, exactly the same problem there. Thanks I’ll try the 1ms timer trick. But isn’t this automagical? Also have to try ScheduledThreadPoolExecutor. I think the best is to sync with vsync, but that works only with fullscreen (btw that’s another problem…tearing).

How flash does its timing? And how they prevent tearing?

edit: isn’t the nanoTime inacurracy just an old bug? It’s useless then…
edit2: I see neoskunk has the same problem, sry for starting same thread…

another thing you should look at is are you creating lots of garbage or using up lots of memory?

yes it seems that path motion “jitter” every n second, probably a tiny issue that Brakeen forgot to patch, about the vsync there are in “full java2d” pretty hard problem wiht that :-\

with 60 FPS this wont affect user experience
[/quote]
Depends on the user I suppose :slight_smile: I found it very noticeable and thought it gave the whole game a poorly-made rickety feel. Someone else might not notice altogether, though.

It also depends on the game. If you have lots of fast-moving objects, or are engaged in trying to carefully maneuver something, it’ll be a lot more noticeable than if you have a mostly static screen.

The Thead.sleep(Long.MAX_VALUE) may be automagical, but is a (relatively) well known solution to this problem…

here is a simple sample of an animation using System.currentTimeMillis() rendering at 100FPS

http://demo.dzzd.net/SimpleSample/

really fast done, but does not seems to “jerk” so much ?

Source Code :

import java.awt.*;
import java.applet.*;

public class testAnim extends Applet implements Runnable 
{
	Image imageBack;
	
	public void start() 
	{
		Thread t=new Thread(this);
		t.start();
	}

	public void draw(Graphics g) 
	{
		if(g==null)
			return;
		if(imageBack==null)
			imageBack=this.createImage(this.getSize().width,this.getSize().height);
			
		Graphics g2=imageBack.getGraphics();
		posX=50.0*Math.sin(System.currentTimeMillis()*0.001)+(this.getSize().width>>1);	
		posY=50.0*Math.cos(System.currentTimeMillis()*0.001)+(this.getSize().height>>1);
		g2.setColor(Color.red);
		g2.fillRect(0,0,this.getSize().width,this.getSize().height);	
		g2.setColor(Color.black);
		g2.drawString("Welcome to Java!!", (int)posX, (int)posY );
		for(int n=0;n<9;n++)
			g2.fillRect((n%3)*this.getSize().width/3+(int)posX-(this.getSize().width>>1),(n/3)*this.getSize().height/3+(int)posY-(this.getSize().height>>1),50,50 );
		g.drawImage(imageBack,0,0,null);
		
	}
	
	double posX=0.0;
	double posY=0.0;
	int rate=10;// => 100 FPS;
	public void run()
	{
		int nbLoop=0;
		try
		{
			long lastTime=System.currentTimeMillis();
			long startTime=System.currentTimeMillis();
			while(true)
			{
				long time=System.currentTimeMillis();
				while(time-lastTime<rate)
				{
					Thread.sleep(1);
					time=System.currentTimeMillis();
				}
				this.draw(this.getGraphics());
				lastTime+=rate;
				nbLoop++;
				if(nbLoop%100==0)
				{
					System.out.println ("FPS="+(nbLoop*1000/(time-startTime)));
				}
			}
		}
		catch(InterruptedException ie)
		{
			ie.printStackTrace();
		}
		
	}
}

NB: close the java console as it will make little hang

It’s a little hard to tell because the rectangles are moving in a small circle, and not too fast. It seems smooth, though.

Something to keep in mind - the rendering hardly takes any time at all for this example, so the timer will generally high-res because there’s a sleeping thread very often. The problem really starts to show up when your rendering and logic take a bit longer, say in the 5-10ms range, during which time there’s no sleeping thread.

(The infinitely sleeping thread from my earlier post can be replaced with an infinite loop of sleep(1) and works just as well).

I bet if you cycled in a for loop for about that long after rendering, you’d see more hiccups… Would be easier to see if movement was linear, horizontal, and faster.

The hiccups are also more apparent if the movement is player-initiated, too. What I mean is if you move something (such as panning the view around) and there’s a slight hiccup, you notice it a lot more than if you weren’t trying to cause that action and it’s just something happening on its own.

updated… faster and more linear movment, vsync prob appear but not related

Nice! Looks good to me, minus the vsync problem. Still, I think it’d be less smooth if the render + logic took more time. Could also be that some app I’m running is forcing the system to use the high-res timer, though.

This is a highly annoying problem to debug when it happens, let me tell you :slight_smile: Took me a LONG time to run into it because during 99% of dev time I was logged into gmail. Which was forcing the system timer to play nice.

It will be good to get a look at the code sample you say you will post soon!

On the face of it, having smoothness problems at 60 fps makes no sense at all. So I’m thinking something must be either blocking or collapsing.

Collapsing example: scenarios where multiple calls to the event dispatch queue are merged rather than run individually. Blocking example: running a lot of the game logic as well as the rendering through the event dispatch queue. (The latter seems plausible since you are saying it’s worse during user events.)

I’m kind of lazy and am wondering if you would mind providing direct links to the examples you found that also demonstrate this problem?

My experiments with timers is that if one sets them to a given value (e.g., 10 msec or 25 msec) they actually display about 4 or 5 msec more than that (e.g., 14 & 29 respectively). But the variation is pretty consistent. I usually use the util.Timer on its own thread instead of the Swing.Timer which uses the Event dispatch queue. GC can disrupt things a bit, but there are ways to vary GC so the interruption is more evenly spread around. But first, should check the code for blocking or collapsing, it seems to me.