1

I'm learning some swing and awt programming in Java so I decided to make Pong. The Main class is the parent JFrame. It instantiates a Ball and a Paddle and adds them (they are JPanels). However, only the last one added is displayed. How do I fix this?

Code:

public class Main extends JFrame {

public Main() {
    super("Pong");
    add(new Ball());
    add(new Paddle());

    setSize(500, 500);
    setBackground(Color.orange);
    setLocationRelativeTo(null);
    setResizable(false);
    setDefaultCloseOperation(EXIT_ON_CLOSE);
}

public static void main(String[] args) {
    new Main().setVisible(true);
}

}

The Ball class:

public class Ball extends JPanel implements ActionListener {

Timer timer;
private Vec2d position;
private Vec2d velocity;
private Dimension ballSize;

public Ball() {
    super();
    position = new Vec2d(50, 50);
    velocity = new Vec2d(2, 3);
    timer = new Timer(25, this);
    ballSize = new Dimension(40, 40);

    timer.start();
}    


@Override
public void actionPerformed(ActionEvent ae) {
    //Perform game frame logic
    bounceBall();
    repaint(); 
}

@Override
public void paintComponent(Graphics g) {
    super.paintComponent(g);
    g.fillArc((int)position.x, (int)position.y, ballSize.width, 
            ballSize.height, 0, 360);
    position.add(velocity);
}

private void bounceBall() {
    if(position.x < 0 || position.x > getWidth() - ballSize.width) {
        velocity.x *= -1;
    }

    if (position.y < 0|| position.y > getHeight() - ballSize.height) {
        velocity.y *= -1;
    }
}

}

And finally, the Paddle class:

public class Paddle extends JPanel implements ActionListener {

private Vec2d position;
private double yVelocity;

private Rectangle rect;

private Timer timer;


public Paddle() {
    super();
    position = new Vec2d(30, 250);
    yVelocity = 0;

    timer = new Timer(25, this);
    timer.start();
}

@Override
public void paintComponent(Graphics g) {
    super.paintComponent(g);
    g.fillRect((int) position.x, (int) position.y, 20, 40);
}

@Override
public void actionPerformed(ActionEvent ae) {
    repaint();
}

}

Note that Vec2d is simply a small two dimensional Vector class I threw together. Also, the Pong logic (collision between Paddle and ball, scoring, etc) is not implemented. I just want to get it to draw correctly

Thanks in advance for the help!

Jack K
  • 463
  • 5
  • 10
  • Your `Main` class never creates your JPanels instances, by the way. – moonwave99 Dec 29 '12 at 17:13
  • I took them out for debugging purposes and forgot to put them in to ask this question. **Stupid me!** It doesn't work correctly regardless. – Jack K Dec 29 '12 at 17:15
  • Your `Main` class does not use a `layoutManager`. BTW, if you do not explictly use a layout manager it always defaults to `BorderLayout` – Extreme Coders Dec 29 '12 at 17:17
  • +1 for SSCCE, Not relevant to probelm but, 1) Dont extend `JFrame` 2) Dont call `setSize` on `JFrame` rather implement a correct `LayoutManager` and/or override `getPreferredSize` of `JPanel` and return correct size which fits drawings and than call `pack()` on `JFrame` before setting it visible. 3) Always create Swing components on Event Dispatch Thread via `SwingUtiltities.invokeXXX` block. – David Kroukamp Dec 29 '12 at 17:29
  • As JB Nizet and Reimeus have said you are adding your JPanels to the same position, on that I dont believe what you need is a `LayoutManager` at this point as this is about the only time IMO `setLayout(null)` should be used your Entities are extensions of `Component`s and not classes modeled to be a Entity (a class which holds attributes that pertain to an entity like `getX()`, `getY()` etc)- Here is an example of such logic : http://stackoverflow.com/questions/13999506/threads-with-key-bindings/14001011#14001011 – David Kroukamp Dec 29 '12 at 17:35

4 Answers4

1

The first thing to do is to add the JPanels to the content pane of your window, not to the window itself. I'm surprised you didn't get a runtime warning about that.

Also, it looks like you are planning to have each of your panels fill the screen, but paint only a small section of it. If that is really the way you want to do it, then you need to do setOpaque(false) on them so the panels under them can show through. But probably a better solution would be to have a single JPanel that is the drawing surface, and have its paintComponent() pass off the Graphics to each of the game objects to let them draw themselves.

Russell Zahniser
  • 16,188
  • 39
  • 30
1
add(new Ball());
add(new Paddle());

By default, the layout manager of a JFrame is a BorderLayout. And if you don't specify where you want to add a component (BorderLayout.WEST, or EAST, etc.), the it's added at the center. So you add two components at the same place: in the center. So, only one of them is displayed.

JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
1

You are adding the Ball and Paddle to the same BorderLayout.CENTER position so only the last one added, (i.e. the Paddle) is displayed. You could use a GridLayout here to display:

setLayout(new GridLayout(1, 2));
add(new Paddle());
add(new Ball());
Reimeus
  • 158,255
  • 15
  • 216
  • 276
  • I just tried the GridLayout and it displays both of them, but once the ball goes past half the screen (and thus onto the second column of the grid layout), it disappears. – Jack K Dec 29 '12 at 17:34
0

in the Paddle class, you never add the velocity to position with position.add(velocity) like you do in your ball class..

svdotbe
  • 168
  • 1
  • 3
  • 16
  • I said I was trying to fix a drawing issue, and that the game logic was not yet implemented... – Jack K Dec 29 '12 at 17:31