I am making a simple animation in Java and I am trying to make it as smooth as possible.
I use only *.Double inner classes of each Shape object and I set antialiasing in the Graphics2D objects on. It all works as long as I use only the fill() method but if I also use draw() method to draw lines around the same Shape the animation of these lines is choppy - pixel by pixel.
Each of my rectangles on the canvas has this method to paint itself. It is moved every 20ms and the whole canvas is repainted using Timer and TimerListener.
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class AnimationTest {
public static void main(String[] args) {
JFrame frm = new JFrame("Test");
frm.setBounds(200, 200, 400, 400);
frm.setResizable(false);
frm.setLocationRelativeTo(null);
AnimationCanvas a = new AnimationCanvas();
frm.add(a);
frm.setVisible(true);
a.startAnimation();
}
}
class AnimationCanvas extends JPanel {
SimpleSquare[] squares = new SimpleSquare[2];
AnimationCanvas() {
squares[0] = new SimpleSquare(50, 80, true);
squares[1] = new SimpleSquare(160, 80, false);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
for (SimpleSquare c : squares) {
c.paintSquare(g);
}
}
Timer t;
public void startAnimation() {
t = new Timer(30, new Animator());
t.start();
}
private class Animator implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
squares[0].y += 0.10;
squares[1].y += 0.10;
repaint();
}
}
}
class SimpleSquare {
double x;
double y;
Color color = Color.black;
boolean fill;
SimpleSquare(double x, double y, boolean fill) {
this.x = x;
this.y = y;
this.fill = fill;
}
void paintSquare(Graphics g) {
((Graphics2D) g).setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
Shape s = new Rectangle.Double(x, y, 100, 100);
g.setColor(color);
((Graphics2D) g).setStroke(new BasicStroke(2));
if (fill) {
((Graphics2D) g).fill(s);
} else {
((Graphics2D) g).draw(s);
}
}
}
Is there any way to fix this problem? I looked around for quite a while.
I put together this little test and got no significnt issues, I was basically capable of maintaining 50fps even with 1000 rectangles all moving at random speeds in random directions.
UPDATE
The biggest problem you're going to face deals with the fact that the screen only works in whole numbers...
I believe that both squares are actually "jittering", but because the drawen square has such an obvious lack of body, it stands out more. I run this test at roughly 24fps without any issue.
You have:
And
But you could achieve the same by changing to
And
Which does the same, but makes 10 times less loops.
I did not test the code but it is worth a try.
The proper solution is provided by MadProgrammer where he measures the delay and offsets by it.