さて、本当にナノ秒になりたいのであれば、この答えの最後に、ScheduledThreadPoolを使用してそれを行う方法があります。しかし、これは純粋な狂気であり、これは多くの問題につながる可能性があり、結果は期待外れです。私は本当にその道を行くことはありません。
50Hz(つまり、1秒あたり50回のリフレッシュ)を使用すると、適切な結果を達成できるはずです。問題は、ピクセルごとに1ピクセルしか移動できず、ボールの速度を移動の増加にリンクできるという仮定をやめたいということです。
次に例を示します(スライダーをドラッグするだけで結果が表示されます)。
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.net.MalformedURLException;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
public class TestAnimation2 {
private static final int NB_OF_IMAGES_PER_SECOND = 50;
private static final int WIDTH = 800;
private static final int HEIGHT = 600;
private static final int MIN = 0;
private static final int MAX = 100;
private double speed = convert(50);
private double dx;
private double dy;
private double x = WIDTH / 2;
private double y = HEIGHT / 2;
private JFrame frame;
private CirclePanel circle;
private Runnable job;
private long lastMove = System.currentTimeMillis();
protected void initUI() throws MalformedURLException {
frame = new JFrame(TestAnimation2.class.getSimpleName());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(null);
circle = new CirclePanel();
circle.setSize(20, 20);
frame.add(circle);
frame.setSize(WIDTH, HEIGHT);
dx = speed;
dy = speed;
final JSlider slider = new JSlider(MIN, MAX);
slider.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
speed = convert(slider.getValue());
if (dx > 0) {
dx = speed;
} else {
dx = -speed;
}
if (dy > 0) {
dy = speed;
} else {
dy = -speed;
}
}
});
slider.setValue(50);
slider.setLocation(0, 0);
slider.setSize(slider.getPreferredSize());
frame.add(slider);
frame.setVisible(true);
Timer t = new Timer(1000 / NB_OF_IMAGES_PER_SECOND, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
move();
}
});
t.start();
}
protected double convert(double sliderValue) {
return sliderValue + 1;
}
protected void move() {
x += dx;
y += dy;
if (x + circle.getWidth() > frame.getContentPane().getWidth()) {
x = frame.getContentPane().getWidth() - circle.getWidth();
dx = -speed;
} else if (x < 0) {
x = 0;
dx = speed;
}
if (y + circle.getHeight() > frame.getContentPane().getHeight()) {
y = frame.getContentPane().getHeight() - circle.getHeight();
dy = -speed;
} else if (y < 0) {
y = 0;
dy = speed;
}
circle.setLocation((int) x, (int) y);
circle.repaint();
}
public static class CirclePanel extends JPanel {
public CirclePanel() {
super();
setOpaque(false);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.RED);
g.fillOval(0, 0, getWidth(), getHeight());
}
}
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException,
UnsupportedLookAndFeelException {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
try {
new TestAnimation2().initUI();
} catch (MalformedURLException e) {
e.printStackTrace();
}
}
});
}
}
スケジュールされたスレッドプールを使用した例を次に示します(非常に危険で残念です)
import java.awt.Color;
import java.awt.Graphics;
import java.net.MalformedURLException;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.SwingUtilities;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
public class TestAnimation2 {
private static final int WIDTH = 800;
private static final int HEIGHT = 600;
private static final int SLOWEST_RATE = 10000000;
private static final int FASTEST_RATE = 1000;
private static final int RANGE = SLOWEST_RATE - FASTEST_RATE;
private static final int MIN = 0;
private static final int MAX = 100;
private double dx;
private double dy;
private double x = WIDTH / 2;
private double y = HEIGHT / 2;
private volatile long delay = convert(50);
private JFrame frame;
private CirclePanel circle;
private Runnable job;
private long lastMove = System.currentTimeMillis();
protected void initUI() throws MalformedURLException {
frame = new JFrame(TestAnimation2.class.getSimpleName());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(null);
circle = new CirclePanel();
circle.setSize(20, 20);
frame.add(circle);
frame.setSize(WIDTH, HEIGHT);
dx = 1;
dy = 1;
final ScheduledExecutorService sheduledThreadPool = Executors.newScheduledThreadPool(1);
final JSlider slider = new JSlider(MIN, MAX);
slider.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
delay = convert(slider.getValue());
}
});
slider.setValue(50);
slider.setLocation(0, 0);
slider.setSize(slider.getPreferredSize());
frame.add(slider);
frame.setVisible(true);
job = new Runnable() {
@Override
public void run() {
move();
sheduledThreadPool.schedule(job, delay, TimeUnit.NANOSECONDS);
}
};
sheduledThreadPool.schedule(job, delay, TimeUnit.NANOSECONDS);
}
protected long convert(float sliderValue) {
return (long) (SLOWEST_RATE - sliderValue / (MAX - MIN) * RANGE);
}
protected void move() {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
System.err.println("Ellapsed " + (System.currentTimeMillis() - lastMove) + " delay is " + (double) delay / 1000000 + " ms");
x += dx;
y += dy;
if (x + circle.getWidth() > frame.getContentPane().getWidth()) {
x = frame.getContentPane().getWidth() - circle.getWidth();
dx = -1;
} else if (x < 0) {
x = 0;
dx = 1;
}
if (y + circle.getHeight() > frame.getContentPane().getHeight()) {
y = frame.getContentPane().getHeight() - circle.getHeight();
dy = -1;
} else if (y < 0) {
y = 0;
dy = 1;
}
circle.setLocation((int) x, (int) y);
frame.repaint();
lastMove = System.currentTimeMillis();
}
});
}
public static class CirclePanel extends JPanel {
public CirclePanel() {
super();
setOpaque(false);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.RED);
g.fillOval(0, 0, getWidth(), getHeight());
}
}
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException,
UnsupportedLookAndFeelException {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
try {
new TestAnimation2().initUI();
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
}
}