Planetalia - Java Training

Training and Consulting

Home

Tutorial - Writing a Space Invaders game in Java

  Previous Page - Flicker Current Page - 11 - JDK Support for Double Buffering   Next Page - Counting FPS
  Return to the index of free Java tutorials  

JDK Support for Double Buffering

(c) Alexander Hristov

The double-buffer approach is so common that starting from JDK 1.4, Java provides a built-in mechanism for performing double buffering.

The class that does all the magic is called BufferStrategy and it is located in the java.awt.image package. Using this class is very easy:

  1. First we must decide which window or component is the one that will make use of double buffering. We must always choose the component upon which we will be painting (in our case, the class Invaders itself)
  2. We call the method createBufferStratgy(n) of the chosen component, passing as parameter the number of buffers we wish to have. Not all systems support having more than two buffers.
  3. We use the method getBufferStrategy() of the component to obtain an instance of BufferStrategy. This class represents basically a chain of buffers in memory - as many as we requested in our createBufferStrategy() call.
  4. In any single moment there's a "drawing buffer" and a "visible buffer". To paint on the hidden off-screen buffer, we call the getDrawGraphics() of the BufferStrategy instance previously obtained..
  5. When we have finished darwing, we call the show() method of the BufferStrategy instance, signalling that the buffer is ready for viewing.

Using this approach, our code now becomes:


1     package version11;
2     /**
3      * Curso B?sico de desarrollo de Juegos en Java - Invaders
4      * 
5      * (c) 2004 Planetalia S.L. - Todos los derechos reservados. Prohibida su reproducci?n
6      * 
7      * http://www.planetalia.com
8      * 
9      */
10    
11    
12    import java.awt.Canvas;
13    import java.awt.Color;
14    import java.awt.Dimension;
15    import java.awt.Graphics;
16    import java.awt.event.WindowAdapter;
17    import java.awt.event.WindowEvent;
18    import java.awt.image.BufferStrategy;
19    import java.awt.image.BufferedImage;
20    import java.net.URL;
21    import java.util.HashMap;
22    
23    import javax.imageio.ImageIO;
24    import javax.swing.JFrame;
25    import javax.swing.JPanel;
26    
27    public class Invaders extends Canvas {
28      public static final int WIDTH = 640;
29      public static final int HEIGHT = 480;
30      public static final int SPEED = 10;
31      
32 public BufferStrategy strategy;
33 public HashMap sprites; 34 public int posX,posY,vX; 35 36 public Invaders() { 37 sprites = new HashMap(); 38 posX = WIDTH/2; 39 posY = HEIGHT/2; 40 vX = 2; 41 42 JFrame ventana = new JFrame("Invaders"); 43 JPanel panel = (JPanel)ventana.getContentPane(); 44 setBounds(0,0,WIDTH,HEIGHT); 45 panel.setPreferredSize(new Dimension(WIDTH,HEIGHT)); 46 panel.setLayout(null); 47 panel.add(this); 48 ventana.setBounds(0,0,WIDTH,HEIGHT); 49 ventana.setVisible(true); 50 ventana.addWindowListener( new WindowAdapter() { 51 public void windowClosing(WindowEvent e) { 52 System.exit(0); 53 } 54 }); 55 ventana.setResizable(false);
56 createBufferStrategy(2); 57 strategy = getBufferStrategy();
58 requestFocus(); 59 } 60 61 public BufferedImage loadImage(String nombre) { 62 URL url=null; 63 try { 64 url = getClass().getClassLoader().getResource(nombre); 65 return ImageIO.read(url); 66 } catch (Exception e) { 67 System.out.println("No se pudo cargar la imagen " + nombre +" de "+url); 68 System.out.println("El error fue : "+e.getClass().getName()+" "+e.getMessage()); 69 System.exit(0); 70 return null; 71 } 72 } 73 74 public BufferedImage getSprite(String nombre) { 75 BufferedImage img = (BufferedImage)sprites.get(nombre); 76 if (img == null) { 77 img = loadImage("res/"+nombre); 78 sprites.put(nombre,img); 79 } 80 return img; 81 } 82 83 public void paintWorld() {
84 Graphics g = strategy.getDrawGraphics();
85 g.setColor(Color.black); 86 g.fillRect(0,0,getWidth(),getHeight()); 87 g.drawImage(getSprite("bicho.gif"), posX, posY,this);
88 strategy.show();
89 } 90 91 92 93 public void updateWorld() { 94 posX += vX; 95 if (posX < 0 || posX > WIDTH) vX = -vX; 96 } 97 98 public void game() { 99 while (isVisible()) { 100 updateWorld(); 101 paintWorld(); 102 try { 103 Thread.sleep(SPEED); 104 } catch (InterruptedException e) {} 105 } 106 } 107 108 public static void main(String[] args) { 109 Invaders inv = new Invaders(); 110 inv.game(); 111 } 112 }

Using the built-in support for double buffering is better than the hand made approach because in many video systems, there's no need to copy the off-screen image onto the screen. Instead, the video adapter allows the OS to change the pointer that specifies where the video memory begins. So if the OS just changes this pointer to point to the off-screen image, it will be instantly shown. In these cases, each of the off-screen images which can be instantly shown are usually called "pages", and the technique, page-flipping. The technique is highly dependant on the video hardware, so we could not use it if we did our double buffering by hand. However, the JRE has access to the OS and as such, can take advantage of this method if the video hardware allows it. Using BufferStrategy, we get all these advantages automatically



Do you want to be notified when new tutorials or lessons are published? Press here


Full list of Java source files for this step

Invaders.java      

Full list of resources

bicho.gif bicho0.gif bicho1.gif bicho2.gif
bombD.gif bombDL.gif bombDR.gif bombL.gif
bombR.gif bombU.gif bombUL.gif bombUR.gif
disparo.gif disparo0.gif disparo1.gif disparo2.gif
explosion.wav misil.gif missile.wav musica.wav
nave.gif oceano.gif photon.wav test.gif
Thumbs.db      

  Previous Page - Flicker Current Page - 11 - JDK Support for Double Buffering   Next Page - Counting FPS
  Return to the index of free Java tutorials  

(c) 2004 Planetalia S.L. All rights reserved. Unauthorized reproduction and/or mirroring is not permitted