Java-Gaming.org Hi !
Featured games (83)
games approved by the League of Dukes
Games in Showcase (524)
Games in Android Showcase (127)
games submitted by our members
Games in WIP (593)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  Smooth animation with pure java?  (Read 2729 times)
0 Members and 1 Guest are viewing this topic.
Offline peter65

Junior Newbie





« Posted 2011-04-18 18:10:13 »

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?
Offline DzzD
« Reply #1 - Posted 2011-04-18 18:15:37 »

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

Offline peter65

Junior Newbie





« Reply #2 - Posted 2011-04-18 18:22:16 »

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.
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline DzzD
« Reply #3 - Posted 2011-04-18 18:25:39 »

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

Offline avm1979
« Reply #4 - Posted 2011-04-18 18:44:36 »

Windows, right?

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

Something like:
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
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.

Offline DzzD
« Reply #5 - Posted 2011-04-18 19:06:26 »

Quote
Having a sleeping thread forces the VM to use the high-precision timer
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

Offline avm1979
« Reply #6 - Posted 2011-04-18 19:08:58 »

Quote
Having a sleeping thread forces the VM to use the high-precision timer
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

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.

Offline DzzD
« Reply #7 - Posted 2011-04-18 19:14:09 »

Quote
Having a sleeping thread forces the VM to use the high-precision timer
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

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.
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 Smiley 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

Offline avm1979
« Reply #8 - Posted 2011-04-18 19:23:44 »

sleeping is not what I was thinking about, skipping one frame will not make an animation looking "choppy"
(soort to quote this word but to be true I% dont know it Smiley)

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

you can get smart animation using currentTimeMillis using something like :
while(notTimeTorender) Sleep(1) ;
not sure but I remenber to have talker about that in another post, basically neither do Sleep(someTime) always while(something) sleep(1)

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.

Offline DzzD
« Reply #9 - Posted 2011-04-18 19:32:22 »

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.
hehe I know I know Wink http://www.java-gaming.org/topics/constant-frame-rate-and-smooth-animation/22933/msg/189842/view.html#msg189842

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

Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline DzzD
« Reply #10 - Posted 2011-04-18 19:34:14 »

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

Offline peter65

Junior Newbie





« Reply #11 - Posted 2011-04-18 19:39:03 »

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..
Offline kappa
« League of Dukes »

JGO Kernel


Medals: 78
Projects: 15


★★★★★


« Reply #12 - Posted 2011-04-18 19:42:33 »

another thing you should look at is are you creating lots of garbage or using up lots of memory?
Offline DzzD
« Reply #13 - Posted 2011-04-18 19:42:52 »

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?
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  Undecided

Offline avm1979
« Reply #14 - Posted 2011-04-18 19:46:37 »

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

Depends on the user I suppose Smiley  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.

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).

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


Offline DzzD
« Reply #15 - Posted 2011-04-18 20:37:50 »

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 :

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  
57  
58  
59  
60  
61  
62  
63  
64  
65  
66  
67  
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

Offline avm1979
« Reply #16 - Posted 2011-04-18 20:56:53 »

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.

Offline DzzD
« Reply #17 - Posted 2011-04-18 21:06:15 »

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

Offline avm1979
« Reply #18 - Posted 2011-04-18 21:25:33 »

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 Smiley  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.

Offline philfrei
« Reply #19 - Posted 2011-04-18 22:06:12 »

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.

"It's after the end of the world! Don't you know that yet?"
Offline pitbuller
« Reply #20 - Posted 2011-04-19 07:57:42 »

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 Smiley  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.
I have noticed that my little car game run at 90fps if I have spotify on. 90fps might sounds good but game is limited to 60fps and this can cause some problems.
Offline peter65

Junior Newbie





« Reply #21 - Posted 2011-04-19 10:35:45 »

Here's some of the code (it's not all that I tryed, have to test the 1ms sleep)
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  
57  
58  
59  
60  
61  
62  
63  
64  
65  
66  
67  
68  
69  
70  
71  
72  
73  
74  
75  
76  
77  
78  
79  
80  
81  
82  
83  
84  
85  
86  
87  
88  
89  
90  
91  
92  
93  
94  
95  
96  
97  
98  
99  
100  
101  
102  
103  
104  
105  
106  
107  
108  
109  
110  
111  
   public void setupStrategy(){
      createBufferStrategy(2);
      bufstrategy = getBufferStrategy();  
   }

   public void runAnimation(){      
      //note: I was experimenting with separate thread, doesn't change anything..
      startNanos = System.nanoTime();
     
      //change timer resolution
      Thread thread = new Thread(new Runnable() {
           public void run() {
             try {
               Thread.sleep(Long.MAX_VALUE);
             } catch (Exception e) { }
           }
         });
      thread.setDaemon(true);
      thread.start();
         
      Thread t = new Thread(new Runnable(){
         public void run(){
            while(true){
               gameLoopBody();
            }
         }
      });
      t.start();
   }

   public void gameLoopBody() {              
     
         long frameStart = System.nanoTime();
         boolean needwait = true;
         
         //update state (just simple..)
         x += 3*dir;
               
         if (x > 800){
            dir=-1;            
         } else
         if (x<5){
            dir=1;        
         }
         
         //show      
         do {
            do {              
               Graphics2D gg = (Graphics2D) bufstrategy.getDrawGraphics();
               
               Point mousePos = getMousePosition();
               
               gg.fillRect(0, 0, getWidth(), getHeight()); //clear bg
               
               //note: images are some random PNGs from net with transparency
               //(I originaly wanted to test the performance of that)
               
               if(mousePos!=null)
                  gg.drawImage(bgi,mousePos.x,mousePos.y, null);
               
               gg.drawImage(luigi,x,40,80,80,null);
               gg.drawImage(luigi,50,40,200,200,null);
               gg.drawImage(luigi,90,80,100,100,null);
               gg.drawImage(luigi,20,90,200,200,null);
               gg.drawImage(luigi,40,200,100,100,null);
               
               if( mousePos!=null )
                  gg.drawImage(luigi,mousePos.x,mousePos.y,50,50,null);
               
               gg.setColor(Color.WHITE);                              
               gg.drawString("FPS: "+String.format("%1$010.2f",this.fps),10,10);
               
               
               gg.dispose();
               
            } while (bufstrategy.contentsRestored());
           
            //schedule swap
            if( needwait ){
               int timing=1;
               //account there state changes and drawing
               long timeout = (int)((1000.0/60.0)*1000000)-(System.nanoTime()-frameStart);
//               long timeout = (int)((1000.0/60.0)*1000000);

               if(timing==1){
               if(timeout>0)
                  LockSupport.parkNanos(timeout);
               }
               
               //note: this is nearly perfect, i don't account anything to the timeout
               if(timing==2){
               long st = System.nanoTime();
               while( (int)(1000.0/60.0)*1000000-(System.nanoTime()-st) > 0 )
                  Thread.yield();
               }
               
               lastTime = System.nanoTime();
               needwait=false;
            }        
         
            bufstrategy.show();                        
           
         } while (bufstrategy.contentsLost());
                 
         frames++;
         
         long currTime = System.nanoTime();        
         fps = ((long)1.0/((currTime-frameStart)/1e9));
         
         
   }


I also found, that the performance is good only with opengl pipeline. This is intel gma4500m.
Pages: [1]
  ignore  |  Print  
 
 
You cannot reply to this message, because it is very, very old.

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

toopeicgaming1999 (46 views)
2014-11-26 15:22:04

toopeicgaming1999 (38 views)
2014-11-26 15:20:36

toopeicgaming1999 (8 views)
2014-11-26 15:20:08

SHC (24 views)
2014-11-25 12:00:59

SHC (24 views)
2014-11-25 11:53:45

Norakomi (25 views)
2014-11-25 11:26:43

Gibbo3771 (23 views)
2014-11-24 19:59:16

trollwarrior1 (36 views)
2014-11-22 12:13:56

xFryIx (75 views)
2014-11-13 12:34:49

digdugdiggy (52 views)
2014-11-12 21:11:50
Understanding relations between setOrigin, setScale and setPosition in libGdx
by mbabuskov
2014-10-09 22:35:00

Definite guide to supporting multiple device resolutions on Android (2014)
by mbabuskov
2014-10-02 22:36:02

List of Learning Resources
by Longor1996
2014-08-16 10:40:00

List of Learning Resources
by SilverTiger
2014-08-05 19:33:27

Resources for WIP games
by CogWheelz
2014-08-01 16:20:17

Resources for WIP games
by CogWheelz
2014-08-01 16:19:50

List of Learning Resources
by SilverTiger
2014-07-31 16:29:50

List of Learning Resources
by SilverTiger
2014-07-31 16:26:06
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!