0

Im new to more dynamic java swing programing. I have of course used the regular swing components before with Buttons, Panels and more.

So I'm trying to make a very basic pong game using Swing and Graphics2D. I previously made a painting program which i succeeded to do.

My issue is that the graphics stutters heavily when the program is running. So far I have only implemented the ball and its just choosing a random direction and starts to bounce around in the panel. Which works. But, I can only see the ball if I'm constantly resizing the frame all the time, otherwise it stutters so heavily that it looks blank. In the first second or so you can actually see the ball moving, but heavily stuttering, and then the panel start to seem blank.

Relevant code and structure:

Main parts of the program are the Controller and Frame class. Where the Controller implements runnable and contains a run method that does the game updating.

The Frame class extends JFrame and contains a private instance variable JPanel gamePanel where all the graphics are painted. JFrame also has a Overridden paint(); method

When the Controller updates the program it calls a class in Frame called updateGraphics() which previously called paint(getGraphics());

public class Frame extends JFrame {

    private JPanel gamePanel;

    ....

    public void paint(Graphics g) {
        super.paint(g);

        label.setText(Integer.toString(ball.getPos().x) + ", " +  Integer.toString(ball.getPos().y));
        Graphics2D g2 = (Graphics2D) gamePanel.getGraphics();
        g2.setStroke(new BasicStroke(2));
        //g2.drawRect(0, 0, gamePanel.getWidth(), gamePanel.getHeight());

        try{
            //Draws the ball
            g2.fillOval(ball.getPos().x, ball.getPos().y, 10, 10);

            //Draws the player1(left) shield
            g2.setStroke(new BasicStroke(2));
            g2.drawLine(playerShield.getNorthX(), playerShield.getNorthY(), playerShield.getSouthX(), playerShield.getSouthY());
            g2.drawLine(playerShield.getNorthX(), playerShield.getNorthY(), playerShield.getSouthX(), playerShield.getSouthY());

            //Draws the computer/Player2(right) Shield
            g2.drawLine(computerShield.getNorthX(), computerShield.getNorthY(), computerShield.getSouthX(), computerShield.getSouthY());
            g2.drawLine(computerShield.getNorthX(), computerShield.getNorthY(), computerShield.getSouthX(), computerShield.getSouthY());
        } catch(Exception e) {
            System.out.println(e);
        }
    }

    ...

    public void updateGraphics() {
          paint(getGraphics());
    }

    //Another version of the updateGraphics i have tried to use with as little success

    public void updateGrapgics() {
         gamePanel.validate();
         gamePanel.repaint();
    }

}

When searching I have found people that says that I should and shouldn't use the paint or repaint method.

Can someone explain to me why its stuttering and how I should do to make it stutter-free?

k4sia
  • 414
  • 1
  • 6
  • 18
BOSIG
  • 13
  • 1
  • 7
  • "Swing programs should override `paintComponent()` instead of overriding `paint()`."—[*Painting in AWT and Swing: The Paint Methods*](http://www.oracle.com/technetwork/java/painting-140037.html#callbacks). An example is seen [here](http://stackoverflow.com/a/14001011/230513). – trashgod Dec 31 '13 at 14:45
  • What is in the controller, a loop calling updateGraphics()? – Krystian Lieber Dec 31 '13 at 14:48
  • @trashgod So should I make the ´gamePanel´ to a own class that extends ´JPanel´ and override its ´paintComponent´? – BOSIG Dec 31 '13 at 14:50
  • @KrystianLieber In the `Controllers run()` method there is an infinite loot that calls `updateGrapgics()` every 1000/60 (for 60 fps) second, which is in my post. – BOSIG Dec 31 '13 at 14:54
  • @BOSIG: Yes, for [example](http://stackoverflow.com/a/14001011/230513). – trashgod Dec 31 '13 at 15:09

2 Answers2

1

There's no need to implement double-buffering or other tricks. Just do the following:

public class SomeVisualObject extends JComponent {
  public void paintComponent(Graphics g) {
    Graphics2D g2d = (Graphics2D)g;  
    // paint things
  }
}

...
final SomeVisualObject obj = new SomeVisualObject()
frame.add(obj);
...

final Timer repaintTimer = new Timer(20, new ActionListener() {
  public void actionPerformed(ActionEvent evt) {
    // do some stuff here, for example calculate game physics.
    // repaint actually does not repaint anything, but enqueues repaint request
    obj.repaint();
  }
});
repaintTimer.start();

and it will run and paint smoothly, without glitches.

Just don't mess with the loops. Swing runs it's own event loop, which is vital for repaints and other stuff.

See a complete and working example of 2d game object (bouncing ball) here: https://gist.github.com/akhikhl/8199472

akhikhl
  • 2,552
  • 18
  • 23
0

I think that you should implement some kind of double buffering.

Your problem is simillar to this one Java Panel Double Buffering and this tutorial should help you a lot http://www.cokeandcode.com/info/tut2d.html.

Community
  • 1
  • 1
Krystian Lieber
  • 481
  • 3
  • 10