Search code examples
javaswinggifgraphics2danimated-gif

Multiple instances of the same animated GIF in a Canvas (Java)


So I'm making a game where you can put bombs on the location of your character. Each bomb is associated with a GIF image when the bomb is displayed and eventually go BOOM (think about Bomberman).

The problem was, when i tried to paint more than one bomb on the screen, it was painted from the last frame of the GIF. Investigating, I found the method image.flush() to reset the GIF cicle but now the problem is that every time I paint a second bomb on the screen, the GIF cycle is reset for all previously bombs on screen.

Here is my constructor for each bomb:

public Tnt(int x, int y){
    this.x = x;
    this.y = y;
    ImageIcon ii = new ImageIcon("src/main/resources/modelObjects/tnt.gif");
    image = ii.getImage();
    image.flush();
}

Every bomb i create enters an ArrayList (listTnt) and is removed after 6 secs, so i only paint the bombs already active.

Here is my method for drawing:

public void draw(Graphics2D g2d, JPanel board){
    for(Tnt tnt: listTnt){          
        g2d.drawImage(tnt.getImage(), tnt.getX(), tnt.getY(), board);
    }
}

EDIT: Seems that the problem was ImageIcon, since it reuses the image using Toolkit.getImage. Instead, Toolkit.createImage create a not reusable image.

Here is my new constructor for Tnt that worked perfectly:

public Tnt(int x, int y){
    this.x = x;
    this.y = y;
    Toolkit t = Toolkit.getDefaultToolkit ();
    image = t.createImage("src/main/resources/modelObjects/tnt.gif");
}

I dont even need image.flush() now. Thank you all.


Solution

  • The underlying Image is being reused amongst each ImageIcon. Judging by the OpenJDK source code, it appears to be due to the fact that each simply requests the Image via Toolkit.getImage. This method has a nifty caveat, however, which explains the issue at hand:

    The underlying toolkit attempts to resolve multiple requests with the same filename to the same returned Image.

    Instead, you should skip the ImageIcon step completely (since it's inappropriate to be using a Swing class unnecessarily in the first place), and instead call Toolkit.createImage, which states in the documentation:

    The returned Image is a new object which will not be shared with any other caller of this method or its getImage variant.

    Good luck.