Search code examples
javaswingdrawpaint

Painting a group of objects in a JPanel


I'm pretty new to Java and the GUI world. Right now I'm trying to create a really basic space shooter. To create it I started creating a JFrame, in which I've later on put a personal extension of a JPanel called GamePanel, on which I'm now trying to display all my components. Until here it's all pretty clear, the problem comes now: I have my GamePanel in which I display my player, and on the KeyEvent of pressing S the player should shoot the Bullets. I've managed the bullets as an Array, called Shooter[], of Bullet Objects, created by myself this way:

public class Bullet implements ActionListener{

    Timer Time = new Timer(20, this);

    private int BulletY = 430;
    public int PlayerX;
    public Rectangle Bound = new Rectangle();

    public Bullet(int playerx) {
        this.PlayerX = playerx;
        Time.start();
    }

    public void draw(Graphics g){
        g.setColor(Color.RED);
        g.fillRect(PlayerX + 2, BulletY, 3, 10);

        g.dispose();
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        if (Time.isRunning()) {
            BulletY = BulletY - 5;
            Bound = new Rectangle (PlayerX + 2, BulletY, 3, 10);
        }
    }

}

I thought that calling the draw method in the GamePanel's paint() method would have allowed me to display both all the bullets shot and the player. What actually happens is that at the start it seems allright, but when I press S the player disappears and just one bullet is shot. Can you explain me why? This is how my paint() method looks like:

public void paint(Graphics g) {
        g.setColor(Color.BLACK);
        g.fillRect(0, 0, 500, 500);

        for(int i = 0; i < BulletsCounter; i++) {
            Shooter[i].draw(g);
        }

        g.setColor(Color.RED);
        g.fillRect(PlayerX, PlayerY, 20, 20);

        //System.out.println("Here I should have painted the player...");

        g.dispose();
    }

BulletsCounter is a counter I've created to avoid any NullPointerExceptions in painting the whole array, it increases when S is pressed and so another bullet of the array is initialized and shot. Thank you for your patience, I'm new to the site, so warn me for any mistake.


Solution

  • You've several significant problems, the biggest given first:

    • You're disposing a Graphics object given to you by the JVM. Never do this as this will break the painting chain. Instead, only dispose of a Graphics object that you yourself have created.
    • You're drawing within paint which is not good for several reasons, but especially bad for animation since you don't have automatic double buffering of the image
    • You don't call the super painting method within your override and thus don't allow the JPanel to do house-keeping painting.

    Recommendations:

    • Don't dispose of the Graphics object, not unless you, yourself, create it, for example if you extract one from a BufferedImage.
    • Override the JPanel's paintComponent method, not its paint method to give you double buffering and smoother animation.
    • And call super.paintComponent(g) first thing in your override to allow for housekeeping painting