user498001
user498001

Reputation: 244

Java Physics loop (repaint on interval) is choppy unless mouse is moving

I have a simple physics loop that does a calculation for a time interval, waits for the interval to pass, and then renders the results on the screen. It's very simple code (even though the timing is probably wrong, but that's exactly what I'm trying to learn about) and works well when I am moving the mouse around the screen.

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

    }

}

The last bit about printing the time difference was just a sanity check to make sure that it was in fact calling around the requested interval. The results are fairly consistent so I don't see why there should be any choppiness.

As I mentioned above, this code works great if I a moving the mouse around the screen, everything is smooth.

If I am not moving the mouse it becomes very choppy until I start moving the mouse over the application.

I assume this is something simple, but I hope that you guys can help me. Thank you.

Upvotes: 1

Views: 438

Answers (1)

user498001
user498001

Reputation: 244

Alright, it looks like my problem was I was drawing directly to g in paint(). After replacing with the following everything worked correctly.

 @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);
  }

I was considering deleting this code snippet because it's rough and shameful, but maybe it will help someone else. Happy coding.

Upvotes: 1

Related Questions