Planetalia - Java Training

Training and Consulting

Home

Tutorial - Writing a Space Invaders game in Java

  Previous Page - Optimizing even more our image loading process Current Page - 07 - The Game Main Loop   Next Page - Cleaning the Screen
  Return to the index of free Java tutorials  

The Game Main Loop

(c) Alexander Hristov

Now that we have the tools to load and paint images, it's about time to see how we can make things happen in our Java game. Just as all Windows applications have a kernel called Message Loop, which is constantly receiving incoming events and responding to them, in a very similary way all games have a main loop which constantly performs the following:

  1. Update the "state of the world" or "stage"
  2. Refresh the screen (redraw the world)
  3. Go back to point 1

In the first step is where all monster movements, player actions, level changes, etc... happen. Of course, this is not done in the same method, but it is a clearly different part from the next one, in which the player view of the world is redrawn.

Let's implement this system in our Java game. We'll call the method with the main loop game(). The method that will update the state of the world will be updateWorld() and finally we'll keep the paint() method for the moment as the method charged with redrawing the world.

In this step, "updating the world" will simply mean changing randomly the position of our monster. We'll need two variables called posX and posY that will store the current position, so that the updateWorld() can change them and the paint() can use them for painting the monster in the correct position

With these ideas, our program now is


1     package version07;
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.Dimension;
14    import java.awt.Graphics;
15    import java.awt.event.WindowAdapter;
16    import java.awt.event.WindowEvent;
17    import java.awt.image.BufferedImage;
18    import java.net.URL;
19    import java.util.HashMap;
20    
21    import javax.imageio.ImageIO;
22    import javax.swing.JFrame;
23    import javax.swing.JPanel;
24    
25    public class Invaders extends Canvas {
26      public static final int WIDTH = 640;
27      public static final int HEIGHT = 480;
28      
29      public HashMap sprites;
30      public int posX,posY;
31      
32      public Invaders() {
33        sprites = new HashMap();
34        posX = WIDTH/2;
35        posY = HEIGHT/2;
36        
37        JFrame ventana = new JFrame("Invaders");
38        JPanel panel = (JPanel)ventana.getContentPane();
39        setBounds(0,0,WIDTH,HEIGHT);
40        panel.setPreferredSize(new Dimension(WIDTH,HEIGHT));
41        panel.setLayout(null);
42        panel.add(this);
43        ventana.setBounds(0,0,WIDTH,HEIGHT);
44        ventana.setVisible(true);
45        ventana.addWindowListener( new WindowAdapter() {
46          public void windowClosing(WindowEvent e) {
47            System.exit(0);
48          }
49        });
50        ventana.setResizable(false);
51      }
52      
53      public BufferedImage loadImage(String nombre) {
54        URL url=null;
55        try {
56          url = getClass().getClassLoader().getResource(nombre);
57          return ImageIO.read(url);
58        } catch (Exception e) {
59          System.out.println("No se pudo cargar la imagen " + nombre +" de "+url);
60          System.out.println("El error fue : "+e.getClass().getName()+" "+e.getMessage());
61          System.exit(0);
62          return null;
63        }
64      }
65      
66      public BufferedImage getSprite(String nombre) {
67        BufferedImage img = (BufferedImage)sprites.get(nombre);
68        if (img == null) {
69          img = loadImage("res/"+nombre);
70          sprites.put(nombre,img);
71        }
72        return img;
73      }
74      
75      
76      public void paint(Graphics g) {
77        g.drawImage(getSprite("bicho.gif"), posX, posY,this);
78      }
79      
80 public void updateWorld() { 81 posX = (int)(Math.random()*WIDTH); 82 posY = (int)(Math.random()*HEIGHT); 83 }
84
85 public void game() { 86 while (isVisible()) { 87 updateWorld(); 88 paint(getGraphics()); 89 } 90 }
91 92 public static void main(String[] args) { 93 Invaders inv = new Invaders(); 94 inv.game(); 95 } 96 } 97

We've also used this step to introduce a call to setResizable(false) in the constructor, to prevent the user from resizing our window.

If we run this program, we'll be surprised - our window will be almost instantly filled with a crowd of monsters:

Curso Space Invaders en Java
Where's Wally?

Obviously we have a problem : since it's us who are calling the paint() method by hand, the window does not get erased prior to that, and the image of the monster in its old position remains drawn as the new image is shown.



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 - Optimizing even more our image loading process Current Page - 07 - The Game Main Loop   Next Page - Cleaning the Screen
  Return to the index of free Java tutorials  

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