flashing screen with paint()

As I’ve mentioned before, my current project is a tilebased roguelike in the vein of nethack. All of the objects are displayed simply as characters in a grid. To display them, I’ve chosen to to just use java’s built in graphics.drawString(). After every “step”, I have the paint() method redraw the entire map.

public void paint(Graphics gr){
		super.paint(gr);
		GameObject map[][][] = mainMap.getMap();
		for(int i = 0; i < map.length; i++){
			for(int j = 0; j < map[0].length; j++){
				gr.drawString(Character.toString(map[i][j][0].getChar()), (i * 15) + 15, (j * 15) + 60);
			}
		}
	}

This works, but it causes the screen to flicker with every update. It appears to display a blank screen before displaying the new one. Is their someway to buffer the previous screen, and keep it displayed until the new one is ready to replace it?

Are you double buffering? If not, Look it up. :slight_smile:

Could super.paint() be causing issues? I haven’t looked into java graphics2d in a while but if the method can be overridden then maybe every super.paint() just endlessly calls paint().

Again, I could be completely wrong, but it’s just a thought.

CopyableCougar4

Edit: This person had the same issue, so maybe the solution could help: http://stackoverflow.com/questions/8919345/java2d-drawing-is-flickering

Your code seems like it’s setup right, try clearing the screen manually prior to rendering?


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

	// try clearing the screen manually
	gr.setColor(java.awt.Color.black);
	gr.fillRect(0, 0, windowWidth, windowHeight); // your windows size.

	// now perform game rendering.
	GameObject map[][][] = mainMap.getMap();
	for(int i = 0; i < map.length; i++){
		for(int j = 0; j < map[0].length; j++){
			gr.drawString(Character.toString(map[i][j][0].getChar()), (i * 15) + 15, (j * 15) + 60);
		}
	}
}

Hope it helps.

If not, try adding a call to java.awt.Toolkit.getDefaultToolkit().sync() after your rendering loop is completed.

What it does:
Chris Campbell, from the Java2D team, kindly reminded me that timing the painting operation should be performed by calling Toolkit.sync() after each paint to ensure the drawing commands are flushed to the graphics card.

I’m a noob myself, if that doesn’t fix it I’d suggest looking into rendering via a BufferStrategy as that will most likely fix the flashing.

Double buffering is what you are looking for. It is exactly the “way to buffer the previous screen, and keep it displayed until the new one is ready to replace it”

BufferedImage buffer; // initialized elsewhere

public void paint(Graphics g){
      Graphics gr = buffer.getGraphics();

      super.paint(gr);
      GameObject map[][][] = mainMap.getMap();
      for(int i = 0; i < map.length; i++){
         for(int j = 0; j < map[0].length; j++){
            gr.drawString(Character.toString(map[i][j][0].getChar()), (i * 15) + 15, (j * 15) + 60);
         }
      }

     gr.dispose();
     g.drawImage(buffer, 0, 0, null);
}

but how/where do I initialize the BufferedImage?
Edit: looks like I need a height, width, and imagetype to initialize the BufferedImage. I assume the width and the height is simply the width and height of the window. But what about the imagetype?

Probably in the constructor of the class that contains the paint() method.

Various constructors for BufferedImage: http://docs.oracle.com/javase/7/docs/api/java/awt/image/BufferedImage.html

so I initialized in the constructor
buffer = new BufferedImage(800, 500, BufferedImage.TYPE_INT_RGB);

It solves the flickering, but now all the drawstrings are white…

What were they before? Just set the paint color of [icode]gr[/icode] to the color you want.

sweet…works perfectly. So as I understand it…it looks like the BufferedImage is essentially a second screen to draw on. The new screen is first drawn on the BufferedImage, and once it is fully drawn, it is copied over to the actual screen with g.drawImage(buffer, 0, 0, null);

I’m a little confused about gr.dispose(). It seems like that just deletes the graphics object, but is that really necessary? Wouldn’t be deleted anyways when it goes out of scope at the end of the paint() call?

Pretty much. It works be cause before you where rendering many small changes, so you can see them happening before the image is complete, thus causing flicker. Now the image is drawn on the off-screen image, then blitted to the screen all in one go, so you don’t see the flickering intermediate process.

The object would be garbage collected, yes, but it has special cleanup that you should make sure happens by calling dispose().