-1

I can't understand why this Timer is animating jaggedly. Is this a platform-dependent problem? I'm writing a 2D game using this kind of animation and am frustrated with the uneven frame rate. Here's the code for a simplified example:

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;

import javax.swing.JPanel;

public class AnimationTest extends JPanel
{
    private static final long serialVersionUID = 1L;
    private Point location = new Point(0, 300);
    private int speed = 3;

    public AnimationTest()
    {
        setPreferredSize(new Dimension(800, 600));
    }

    public void timeStep()
    {
        move();
        repaint();
        currentTime = System.nanoTime();
        System.out.println(currentTime - previousTime);
        previousTime = currentTime;
    }

    private void move()
    {
        location.x += speed;
        if(location.x >= 800) location.x = 0;
    }

    @Override
    protected void paintComponent(Graphics g)
    {
        Graphics2D g2d = (Graphics2D) g;
        super.paintComponent(g2d);
        g2d.fillOval(location.x, location.y, 40, 40);
    }
}

And here's the main method:

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import java.util.Timer;
import java.util.TimerTask;

import javax.swing.JFrame;
import javax.swing.WindowConstants;

public class AnimationTestMain
{
    public static void main(String[] args)
    {
        JFrame frame = new JFrame("Test");
        final AnimationTest test = new AnimationTest();
        frame.add(test);
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        frame.pack();
        frame.setVisible(true);

        int animationMethod = 0;

        if(animationMethod == 0)
        {
            new javax.swing.Timer(10, new ActionListener()
            {
                @Override
                public void actionPerformed(ActionEvent e)
                {
                    test.timeStep();
                }
            }).start();
        }
        else if(animationMethod == 1)
        {
            Thread thread = new Thread(new Runnable()
            {
                @Override
                public void run()
                {
                    while(true)
                    {
                        test.timeStep();
                        try
                        {
                            Thread.sleep(10);
                        } catch (InterruptedException e) {}
                    }
                }
            });
            thread.start();
        }
        else if(animationMethod == 2)
        {
            java.util.Timer timer = new Timer();
            timer.scheduleAtFixedRate(new TimerTask()
            {
                @Override
                public void run()
                {
                    while(true)
                    {
                        test.timeStep();
                        try
                        {
                            Thread.sleep(10);
                        } catch (InterruptedException e) {}
                    }
                }
            }, 0, 10);
        }
    }
}

Modifying the animationMethod variable doesn't change much of the result. You can see the uneven frame rate in the nanosecond printouts. Help!

  • How uneven is it...? Can you give a sample printout? – Radiodef Apr 05 '15 at 22:52
  • Where's the CPU time being spent when it hiccoughs? Is it happening whenever a buffer is flushed? Is there any operation (besides animation) you can do with a timer scheduled like that that isn't bursty? – clearlight Apr 05 '15 at 22:53
  • 15629506 15588454 15626427 15554074 15493521 15623861 15574086 15766004 17558948 15506351 15673636 16722515 15402694 15936369 15368313 15617191 15583323 15569980 15657217 15632071 15565363 15488390 15497113 15611033 15612059 15562797 15736241 15469916 15672611 15712123 15665940 15637716 15516614 15593585 15581784 15605388 15600256 15644388 15538678 15536113 15845542 15413470 15583836 15648493 – Pull Nointer Apr 05 '15 at 22:53
  • Are you on a single-user system with adequate configuration and no CPU demanding background jobs hogging the CPUs and cores? – clearlight Apr 05 '15 at 22:53
  • The differences seem like a very small % of the total time of each interval, so that seems like minor noise. Something else must be happening to make it jagged. – clearlight Apr 05 '15 at 22:55
  • The greatest difference there is about 2ms. Remember that those times are in nanoseconds. I would say that's pretty good... Is the animation visibly jumpy or are the times your only basis? – Radiodef Apr 05 '15 at 22:55
  • @Radiodef, just imagine if he was measuring it in yoctoseconds! – clearlight Apr 05 '15 at 22:57
  • If you run the code, the filledOval jerks as it's animated which probably indicates bursts... Task Manager says my CPU is running at 0% and I'm the only user. – Pull Nointer Apr 05 '15 at 22:59
  • Are you using standard graphics buffering techniques for efficiency? http://en.wikipedia.org/wiki/Multiple_buffering – clearlight Apr 05 '15 at 23:00
  • @Radiodef yes it's visibly jumpy – Pull Nointer Apr 05 '15 at 23:05
  • In any case, if you are trying to measure the frame rate, what you should be timing is `paintComponent`, not the update thread. The painting is asynchronous so it doesn't happen immediately after you call `repaint`. – Radiodef Apr 05 '15 at 23:05
  • So the moving of objects in the scene (in this case the oval) and rendering should be in different threads? – Pull Nointer Apr 05 '15 at 23:12

1 Answers1

0

the swing timer is the most unprecise option you got.

There are 2 other options:

  • The Utility Timer (medium precision)
  • Own Thread (highest precision)

Check out this link.

If you choose to make an own thread, check out this tutorial for the game loop.