У меня есть простой физический цикл, который выполняет расчет за промежуток времени, ждет переходного интервала и затем отображает результаты на экране. Это очень простой код (хотя время, вероятно, неверно, но именно то, что я пытаюсь узнать) и хорошо работает, когда я перемещаю мышь по экрану.
package physicssim;
import java.awt.Graphics;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class PhysicsSim extends JFrame {
private static class PhysicsObject {
public PhysicsObject(double x, double y, double v_x, double v_y) {
this.x = x;
this.y = y;
this.v_x = v_x;
this.v_y = v_y;
}
public double x;
public double y;
public double v_x;
public double v_y;
}
PhysicsObject particle;
boolean running = true;
DrawPane drawPane;
public PhysicsSim() {
particle = new PhysicsObject(10,10, .1, .2);
drawPane = new DrawPane(particle);
this.setSize(800,600);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setContentPane(drawPane);
this.setVisible(true);
}
private static class DrawPane extends JPanel {
PhysicsObject p;
public DrawPane(PhysicsObject p) {
this.p = p;
}
@Override
public void paint(Graphics g) {
super.paint(g); //To change body of generated methods, choose Tools | Templates.
g.fillOval((int)p.x, (int) p.y, 10, 10);
}
}
public void start() {
int FPS = 60;
long TIME_BETWEEN_FRAMES_NS = 1000000000/FPS;
// Initial draw
drawPane.repaint();
long lastDrawTime = System.nanoTime();
while(running) {
// Update physics
particle.x+=particle.v_x*(TIME_BETWEEN_FRAMES_NS*.0000001);
particle.y+=particle.v_y*(TIME_BETWEEN_FRAMES_NS*.0000001);
// While there is time until the next draw wait
while(TIME_BETWEEN_FRAMES_NS > (System.nanoTime()-lastDrawTime)) {
try {
Thread.sleep(1);
} catch (InterruptedException ex) {
Logger.getLogger(PhysicsSim.class.getName()).log(Level.SEVERE, null, ex);
}
}
drawPane.repaint();
long currentTime = System.nanoTime();
System.out.println(currentTime - lastDrawTime);
lastDrawTime = currentTime;
}
}
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
PhysicsSim sim = new PhysicsSim();
sim.start();
}
}
Последний бит о печати разницы во времени был просто проверкой здравомыслия, чтобы убедиться, что он фактически вызвал запрошенный интервал. Результаты достаточно последовательно, так что я не понимаю, почему там должна быть никакой зыбь.
Как я уже упоминал выше, этот код отлично работает, если я перемещаю мышь вокруг экрана, все гладко.
Если я не двигаю мышью, он становится очень изменчивым, пока я не начну перемещать указатель мыши над приложением.
Я предполагаю, что это что-то простое, но я надеюсь, что вы, ребята, можете мне помочь. Спасибо.
Хорошо, похоже, моя проблема заключалась в том, что я рисовал непосредственно в g в paint(). После замены следующим образом все работает правильно.
@Override
public void paint(Graphics g) {
BufferedImage img = new BufferedImage(800, 600, BufferedImage.TYPE_3BYTE_BGR);
img.getGraphics().fillOval((int) p.x, (int) p.y, 10, 10);
g.drawImage(img, 0, 0, null);
}
Я думал об удалении этого фрагмента кода, потому что он грубый и позорный, но, возможно, это поможет кому-то другому. Счастливое кодирование.
paintComponent
вместо paint
как это будет в компонентах с двойной буферной емкостью. Кроме того, вы действительно должны использовать getWidth
и getHeight
вместо магических чисел