我一直在使用一个简单的动画Timer上JComponent。但是,当观看动画时,我会遇到难以置信的震荡。我应该采取什么步骤来优化此代码?
Timer
JComponent
MyAnimationFrame
import javax.swing.*; public class MyAnimationFrame extends JFrame { public MyAnimationFrame() { super("My animation frame!"); setSize(300,300); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); add(new AnimationComponent(0,0,50,50)); setVisible(true); } public static void main(String[] args) { MyAnimationFrame f = new MyAnimationFrame(); } }
AnimationComponent
import javax.swing.*; import java.awt.*; public class AnimationComponent extends JComponent implements ActionListener { private Timer animTimer; private int x; private int y; private int xVel; private int yVel; private int width; private int height; private int oldX; private int oldY; public AnimationComponent(int x, int y, int width, int height) { this.x = x; this.y = y; this.height = height; this.width = width; animTimer = new Timer(25, this); xVel = 5; yVel = 5; animTimer.start(); } @Override public void paintComponent(Graphics g) { g.fillOval(x,y,width,height); } @Override public void actionPerformed(ActionEvent e) { oldX = x; oldY = y; if(x + width > getParent().getWidth() || x < 0) { xVel *= -1; } if(y + height > getParent().getHeight() || y < 0) { yVel *= -1; } x += xVel; y += yVel; repaint(); } }
不知道这是否重要,但是我正在使用OpenJDK 1.8.0_121版本。
任何帮助表示赞赏。
在与Yago进行了精彩的讨论之后,我发现问题围绕多个领域展开,很大程度上归因于Java将更新与操作系统和硬件同步的能力,有些是您可以控制的,有些是无法控制的。
受到Yago的示例以及我关于“计时框架”工作原理的“记忆”的启发,我通过提高帧速率(至5毫秒,〜= 200fps)并减小变化增量来测试代码,结果与使用“计时框架”相同,但这使您拥有了原始设计的灵活性。
import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.RenderingHints; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.SwingUtilities; import javax.swing.Timer; public class Test { public static void main(String[] args) { new Test(); } public Test() { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { JFrame frame = new JFrame("Test"); frame.add(new AnimationComponent(0, 0, 50, 50)); frame.setSize(300, 300); frame.setLocationRelativeTo(null); frame.setVisible(true); } }); } public class AnimationComponent extends JComponent implements ActionListener { private Timer animTimer; private int x; private int y; private int xVel; private int yVel; private int width; private int height; private int oldX; private int oldY; public AnimationComponent(int x, int y, int width, int height) { this.x = x; this.y = y; this.height = height; this.width = width; animTimer = new Timer(5, this); xVel = 1; yVel = 1; animTimer.start(); } @Override public void paintComponent(Graphics g) { Graphics2D g2d = (Graphics2D) g.create(); RenderingHints hints = new RenderingHints( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON ); g2d.setRenderingHints(hints); g2d.fillOval(x, y, width, height); } @Override public void actionPerformed(ActionEvent e) { oldX = x; oldY = y; if (x + width > getParent().getWidth() || x < 0) { xVel *= -1; } if (y + height > getParent().getHeight() || y < 0) { yVel *= -1; } x += xVel; y += yVel; repaint(); } } }
如果您需要进一步降低速度,然后进一步降低变化量,则意味着您必须改用doubles,这将导致Shape的API支持双精度值
double
Shape
您应该使用哪个?随你(由你决定。Timing Framework确实非常适合在一段时间内进行线性动画处理,您知道要从一种状态进入另一种状态。对于游戏之类的东西来说,状态不是很好,因为对象的状态可能会从我的周期更改为另一个周期。我敢肯定您可以做到,但是使用简单的“主循环”概念会容易得多- IMHO