Цикл Java Physics (перерисовка на интервале) прерывистый, если мышь не движется

1

У меня есть простой физический цикл, который выполняет расчет за промежуток времени, ждет переходного интервала и затем отображает результаты на экране. Это очень простой код (хотя время, вероятно, неверно, но именно то, что я пытаюсь узнать) и хорошо работает, когда я перемещаю мышь по экрану.

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();

    }

}

Последний бит о печати разницы во времени был просто проверкой здравомыслия, чтобы убедиться, что он фактически вызвал запрошенный интервал. Результаты достаточно последовательно, так что я не понимаю, почему там должна быть никакой зыбь.

Как я уже упоминал выше, этот код отлично работает, если я перемещаю мышь вокруг экрана, все гладко.

Если я не двигаю мышью, он становится очень изменчивым, пока я не начну перемещать указатель мыши над приложением.

Я предполагаю, что это что-то простое, но я надеюсь, что вы, ребята, можете мне помочь. Спасибо.

  • 0
    Подумайте о предоставлении работающего примера, который демонстрирует вашу проблему. Это приведет к меньшему беспорядку и лучшим ответам. «Основной цикл» ужасно неэффективен, сон на 1 миллисекунду достаточно близок, чтобы не спать, чтобы не было никакой разницы. Было бы лучше заранее рассчитать задержку и поспать хотя бы промежуток времени - но это только я ...
  • 0
    @MadProgrammer спасибо. Я разместил полный код. Цикл работает, но только когда вы перемещаете мышь по экрану. Причина не спящего установленного количества времени состоит в том, что Thread.sleep (x) не всегда согласован; В конечном итоге я буду выполнять очень подробные вычисления, это только для того, чтобы вырабатывать глупые ошибки ... как этот.
Показать ещё 5 комментариев
Теги:
swing
awt
animation
paint

1 ответ

1

Хорошо, похоже, моя проблема заключалась в том, что я рисовал непосредственно в 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);
  }

Я думал об удалении этого фрагмента кода, потому что он грубый и позорный, но, возможно, это поможет кому-то другому. Счастливое кодирование.

  • 0
    Хорошо, если это проблема буферизации, используйте paintComponent вместо paint как это будет в компонентах с двойной буферной емкостью. Кроме того, вы действительно должны использовать getWidth и getHeight вместо магических чисел

Ещё вопросы

Сообщество Overcoder
Наверх
Меню