I have two almost identical classes: AnimationFrame1 and AnimationFrame2. Both of these classes display a blue ball moving back and forth horizontally through a 500 x 500 window. The two classes are identical, except for the runAnimation () and createAndShowGUI () methods. In its runAnimation () method, AnimationFrame1 uses a while and sleep method to create an animation loop, while AnimationFrame2 uses a Swing timer. In its createAndShowGUI () method, AnimationFrame1 creates a new thread and calls the runAnimation () method on it, while AnimationFrame2 just calls the runAnimation () method without a new thread.
After compiling both classes, I found that AnimationFrame2, the one that uses the Swing timer, displays a much smoother animation that doesn't stutter as much as the animation displayed in AnimationFrame1, which uses the while and sleep loop. My question is: why is AnimationFrame1 more stuttering in animation than AnimationFrame2? I searched for this reason, but still haven't found anything.
Also, I am obviously a beginner of Java, so please let me know if you see something wrong with my code or know how I could improve it.
Here is the AnimationFrame1:
import javax.swing.*; import java.awt.*; import java.awt.event.ActionListener; import java.awt.event.ActionEvent; import java.awt.image.BufferedImage; class AnimationFrame1 extends JPanel { int ovalX; int prevX; Timer timer; boolean moveRight; BufferedImage img; public AnimationFrame1() { setPreferredSize(new Dimension(500, 500)); } public void runAnimation() { moveRight = true; img = null; ovalX = 0; prevX = 0; while(true) { if (moveRight == true) { prevX = ovalX; ovalX = ovalX + 4; } else { prevX = ovalX - 4; ovalX = ovalX - 4; } repaint(); if (ovalX > 430) { moveRight = false; } if (ovalX == 0) { moveRight = true; } try { Thread.sleep(25); } catch(Exception e) { } } } public void paintComponent(Graphics g) { if (img == null) { GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); GraphicsDevice gs = ge.getDefaultScreenDevice(); GraphicsConfiguration gc = getGraphicsConfiguration(); img = gc.createCompatibleImage(78, 70); Graphics gImg = img.getGraphics(); gImg.setColor(getBackground()); gImg.fillRect(0, 0, getWidth(), getHeight()); gImg.setColor(Color.BLUE); gImg.fillOval(4, 0, 70, 70); gImg.dispose(); } g.drawImage(img, ovalX, 250, null); } public static void createAndShowGUI() { JFrame mainFrame = new JFrame(); final AnimationFrame1 animFrame = new AnimationFrame1(); mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); mainFrame.add(animFrame); mainFrame.pack(); mainFrame.createBufferStrategy(2); mainFrame.setVisible(true); new Thread(new Runnable() { public void run() { animFrame.runAnimation(); } }).start(); } public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { public void run() { createAndShowGUI(); } }); } }
And here is AnimationFrame2:
import javax.swing.*; import java.awt.*; import java.awt.event.ActionListener; import java.awt.event.ActionEvent; import java.awt.image.BufferedImage; class AnimationFrame2 extends JPanel { int ovalX; int prevX; Timer timer; boolean moveRight; BufferedImage img; public AnimationFrame2() { setPreferredSize(new Dimension(500, 500)); } public void runAnimation() { moveRight = true; img = null; ovalX = 0; prevX = 0; timer = new Timer(25, new ActionListener() { public void actionPerformed(ActionEvent ae) { if (moveRight == true) { prevX = ovalX; ovalX = ovalX + 4; } else { prevX = ovalX - 4; ovalX = ovalX - 4; } repaint(); if (ovalX > 430) { moveRight = false; } if (ovalX == 0) { moveRight = true; } } }); timer.start(); } public void paintComponent(Graphics g) { if (img == null) { GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); GraphicsDevice gs = ge.getDefaultScreenDevice(); GraphicsConfiguration gc = getGraphicsConfiguration(); img = gc.createCompatibleImage(78, 70); Graphics gImg = img.getGraphics(); gImg.setColor(getBackground()); gImg.fillRect(0, 0, getWidth(), getHeight()); gImg.setColor(Color.BLUE); gImg.fillOval(4, 0, 70, 70); gImg.dispose(); } g.drawImage(img, ovalX, 250, null); } public static void createAndShowGUI() { JFrame mainFrame = new JFrame(); final AnimationFrame2 animFrame = new AnimationFrame2(); mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); mainFrame.add(animFrame); mainFrame.pack(); mainFrame.createBufferStrategy(2); mainFrame.setVisible(true); animFrame.runAnimation(); } public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { public void run() { createAndShowGUI(); } }); } }