Java:Tutorials:Double Buffering

From GPWiki
Jump to: navigation, search

Introduction

When drawing images that move or are animated, one will often encounter flickering. To remedy this, double buffering is necessary. Double buffering involves first drawing to an offscreen image, and then moving that image to the screen. This way, there is only one change to the screen at once, rather than several changes, one for each sprite. The best way to implement double buffering in Java is to use a BufferStrategy.(Make sure your vm is up to date, or you may encounter a problem.)

Setup

First, your application is going to need a visual output. In order to use the BufferStrategy, you need to extend Window, or something that extends Window. JFrame is a good choice for this. You will need to do a few things with the JFrame in order to make it usable for games:

  • Undecorate the JFrame to make it more suitable for games.
  • Set the size of your JFrame window.*
  • Make the JFrame visible.*
  • Create the BufferStrategy. You can have as many buffers as you like, but it's usually best to stick with 2.

(* These steps are not needed if you're going into fullscreen exclusive mode, which isn't covered here.)

Code Example 1 shows how to do this.

Code Example 1

How to setup your JFrame.

import java.awt.Graphics;
import java.awt.image.BufferStrategy;
import javax.swing.JFrame;
 
public class Game extends JFrame {
 
	public static void main(String[] args) {
		new Game();
	}
 
	public Game() {
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		this.setUndecorated(true);
		this.setSize(800,600);
		this.setVisible(true);
 
		this.createBufferStrategy(2);
 
		gameLoop();
	}
 
	private void gameLoop() {
		// Your game logic goes here.
 
		drawStuff();
	}
 
	private void drawStuff() {
		// Code for the drawing goes here.
	}
 
}

Using the BufferStrategy

I mentioned before that when using double buffering, you draw to an offscreen image. While the BufferStrategy isn't an Image itself, it does own one. Even better, it presents itself as if it were an Image to make things very simple. This means that like an Image, you can get a 'Graphics object from the BufferStrategy. Once you have a Graphics object, all of the standard drawing methods are available to you. Often, it is easiest to pass the Graphics object off to your own objects for them to draw on.

Once you have everything drawn to the offscreen image, it is then time to display it. There are two ways this can be done:

  • Draw from the offscreen image to the screen. (Called blitting.)
  • Tell the program to use the offscreen image as the image for the screen, and vice versa. (Called flipping.)

The second method, flipping, is much faster, as it involves changing a pointer rather than drawing the entire screen. Normally, Java will take care of this for you, but it is possible that flipping is unsupported on some hardware, so it useful to know.

To display your backbuffer, use the BufferStrategy.show() method. There are no parameters. Code Example 2 shows how to do all of this.

Code Example 2

Drawing to the backbuffer, and then showing on the screen.

private void drawStuff() {
	BufferStrategy bf = this.getBufferStrategy();
	Graphics g = null;
 
	try {
		g = bf.getDrawGraphics();
 
		// It is assumed that mySprite is created somewhere else.
		// This is just an example for passing off the Graphics object.
		mySprite.draw(g);
 
	} finally {
		// It is best to dispose() a Graphics object when done with it.
		g.dispose();
	}
 
	// Shows the contents of the backbuffer on the screen.
	bf.show();
 
        //Tell the System to do the Drawing now, otherwise it can take a few extra ms until 
        //Drawing is done which looks very jerky
        Toolkit.getDefaultToolkit().sync();	
}

That's it! If you were originally using a JFrame for your window, and getting the Graphics object directly from the JFrame, this can easily be adapted to fit in. If not, it shouldn't be too hard to fit BufferStrategy into your existing code.

More Information