尽管使用了paintComponent和动画线程,但使用Java/Swing的动画仍然很跳跃
我有一个简单的Java/Swing应用程序,它尝试通过从左向右移动来设置长方体的动画:尽管使用了paintComponent和动画线程,但使用Java/Swing的动画仍然很跳跃,java,swing,animation,Java,Swing,Animation,我有一个简单的Java/Swing应用程序,它尝试通过从左向右移动来设置长方体的动画: public class TestFrame extends JFrame { protected long startTime = new Date().getTime(); public class MainPanel extends JPanel { @Override protected void paintComponent(Graphics g)
public class TestFrame extends JFrame {
protected long startTime = new Date().getTime();
public class MainPanel extends JPanel {
@Override
protected void paintComponent(Graphics g) {
// calculate elapsed time
long currentTime = new Date().getTime();
long timeDiff = currentTime - TestFrame.this.startTime;
// animation time dependent
g.fillRect((int) (timeDiff / 100), 10, 10, 10);
}
}
public class MainLoop implements Runnable {
@Override
public void run() {
while (true) {
// trigger repaint
TestFrame.this.repaint();
}
}
}
public static void main(String[] args) {
new TestFrame();
}
public TestFrame() {
// init window
this.setTitle("Test");
this.setSize(500, 500);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.add(new MainPanel());
this.setVisible(true);
// start render loop
Thread loop = new Thread(new MainLoop());
loop.start();
}
}
问题是动画不干净,长方体(有时)会跳跃几个像素。我已经做了一些研究,根据他们的说法,如果使用paintComponent(而不是paint)和基于时间的动画(而不是基于帧),应该可以很好地工作。我两个都做了,但是动画还是不干净
谁能告诉我出了什么问题吗?你应该让你的while-true循环稍微休息一下。你有点烧坏了你的CPU!您正在生成大量的绘画事件;在线程调度程序决定的某个时间,调度程序会将任务交给事件调度线程,据我所知,该线程可能会将trillon绘画事件折叠为单个事件,并最终执行paintComponent 在下面的示例中,线程睡眠时间为20ms,最大帧速率为50fps。这应该足够了
while (true) {
// trigger repaint
TestFrame.this.repaint();
try {
Thread.sleep(20);
} catch(InterruptedException exc() {
}
}
您在我的机器上的绘制相当平滑,但它在循环中消耗了大量性能,但在速度较慢的机器上,如果您的应用程序忙于执行while或处理绘制事件而不是渲染,我可以想象动画会出现跳跃 根据每次渲染经过的时间更新位置可能更好,我不确定通过
Date
对象比较动画时间的准确性,因此使用System.nanoTime()
比较小的时间差可能更好。例如:
long currentNanoTime = System.nanoTime();
long timeElapsed = currentNanoTime - lastUpdateNanoTime;
lastUpdateNanoTime = currentNanoTime;
...
int newXPosition = oldXPosition + (velocityXInPixelsPerNanoSecond * timeElapsed);
我对你的代码做了一些修改
package com.ggl.testing;
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class TestFrame extends JFrame {
private static final long serialVersionUID = 272649179566160531L;
protected long startTime = System.currentTimeMillis();
public class MainPanel extends JPanel {
private static final long serialVersionUID = 5312139184947337026L;
public MainPanel() {
this.setPreferredSize(new Dimension(500, 30));
}
@Override
protected void paintComponent(Graphics g) {
// calculate elapsed time
long currentTime = System.currentTimeMillis();
long timeDiff = currentTime - TestFrame.this.startTime;
// animation time dependent
g.fillRect((int) (timeDiff / 100), 10, 10, 10);
}
}
public class MainLoop implements Runnable {
@Override
public void run() {
while (true) {
// trigger repaint
TestFrame.this.repaint();
try {
Thread.sleep(20L);
} catch (InterruptedException e) {
}
}
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new TestFrame();
}
});
}
public TestFrame() {
// init window
this.setTitle("Test");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.add(new MainPanel());
this.pack();
this.setVisible(true);
// start render loop
Thread loop = new Thread(new MainLoop());
loop.start();
}
}
同样,考虑使用双缓冲:所以,不确定你想走多远,但是当我学习做动画的游戏循环时,这个教程非常整洁:@ AayMe:看起来很有趣。我来看看:)@mad程序员:嗯,让我想想。帧的时间乘以fps得到的常数是1秒。如果时间增加,fps将降低。我认为你错了。