Planetalia - Java Training

Training and Consulting

Home

Tutorial - Writing a Space Invaders game in Java

  Previous Page - Collision detection Current Page - 21 - Status   Next Page - Score
  Return to the index of free Java tutorials  

Status

(c) Alexander Hristov

Now that we are able to kill the critters, it would be useful to have some kind of score to motivate us to go on. In this step we will add a status bar in the lower end of the screen. Our status bar will consist of the following:

  • A score counter
  • A shield meter
  • A representation of the number of cluster bombs we have
  • As always, our fps counter

Let's start first with the score and the shield meter. These are attributes that belong to the player class, so we add them there, together with their accessor methods. I also found that it was confusing and annoying for the player ship to "bounce" off the walls of the screen (and this is a genuine mistake, not a "planned" one as the previous,really!, so we've also changed the behaviour of the act() method. Now, if the player tries to go off the screen, it simply stays there.


1     /**
2      * Curso B?sico de desarrollo de Juegos en Java - Invaders
3      * 
4      * (c) 2004 Planetalia S.L. - Todos los derechos reservados. Prohibida su reproducci?n
5      * 
6      * http://www.planetalia.com
7      * 
8      */
9     package version21;
10    
11    import java.awt.event.KeyEvent;
12    
13    public class Player extends Actor {
14 public static final int MAX_SHIELDS = 200;
15 public static final int MAX_BOMBS = 5; 16 protected static final int PLAYER_SPEED = 4; 17 protected int vx; 18 protected int vy; 19 private boolean up,down,left,right; 20 private int clusterBombs;
21 private int score; 22 private int shields;
23 24 25 public Player(Stage stage) { 26 super(stage); 27 setSpriteNames( new String[] {"nave.gif"}); 28 clusterBombs = MAX_BOMBS;
29 shields = MAX_SHIELDS;
30 score = 0; 31 } 32
33 public void act() { 34 super.act(); 35 x+=vx; 36 y+=vy; 37 if (x < 0 ) 38 x = 0; 39 if (x > Stage.WIDTH - getWidth()) 40 x = Stage.WIDTH - getWidth(); 41 if (y < 0 ) 42 y = 0; 43 if ( y > Stage.PLAY_HEIGHT-getHeight()) 44 y = Stage.PLAY_HEIGHT - getHeight(); 45 } 46
47 public int getVx() { return vx; } 48 public void setVx(int i) {vx = i; } 49 public int getVy() { return vy; } 50 public void setVy(int i) {vy = i; } 51 52 53 protected void updateSpeed() { 54 vx=0;vy=0; 55 if (down) vy = PLAYER_SPEED; 56 if (up) vy = -PLAYER_SPEED; 57 if (left) vx = -PLAYER_SPEED; 58 if (right) vx = PLAYER_SPEED; 59 } 60 61 public void keyReleased(KeyEvent e) { 62 switch (e.getKeyCode()) { 63 case KeyEvent.VK_DOWN : down = false;break; 64 case KeyEvent.VK_UP : up = false; break; 65 case KeyEvent.VK_LEFT : left = false; break; 66 case KeyEvent.VK_RIGHT : right = false;break; 67 } 68 updateSpeed(); 69 } 70 71 public void keyPressed(KeyEvent e) { 72 switch (e.getKeyCode()) { 73 case KeyEvent.VK_UP : up = true; break; 74 case KeyEvent.VK_LEFT : left = true; break; 75 case KeyEvent.VK_RIGHT : right = true; break; 76 case KeyEvent.VK_DOWN : down = true;break; 77 case KeyEvent.VK_SPACE : fire(); break; 78 case KeyEvent.VK_B : fireCluster(); break; 79 } 80 updateSpeed(); 81 } 82 83 public void fire() { 84 Bullet b = new Bullet(stage); 85 b.setX(x); 86 b.setY(y - b.getHeight()); 87 stage.addActor(b); 88 } 89 90 public void fireCluster() { 91 if (clusterBombs == 0) 92 return; 93 94 clusterBombs--; 95 stage.addActor( new Bomb(stage, Bomb.UP_LEFT, x,y)); 96 stage.addActor( new Bomb(stage, Bomb.UP,x,y)); 97 stage.addActor( new Bomb(stage, Bomb.UP_RIGHT,x,y)); 98 stage.addActor( new Bomb(stage, Bomb.LEFT,x,y)); 99 stage.addActor( new Bomb(stage, Bomb.RIGHT,x,y)); 100 stage.addActor( new Bomb(stage, Bomb.DOWN_LEFT,x,y)); 101 stage.addActor( new Bomb(stage, Bomb.DOWN,x,y)); 102 stage.addActor( new Bomb(stage, Bomb.DOWN_RIGHT,x,y)); 103 } 104
105 public int getScore() { return score; } 106 public void setScore(int i) { score = i; } 107 108 public int getShields() { return shields; } 109 public void setShields(int i) { shields = i; }
110 111 public int getClusterBombs() { return clusterBombs; } 112 public void setClusterBombs(int i) { clusterBombs = i; } 113 114 115 } 116

Now we must change the size of the playing area, since we must reserve a part of the screen for drawing the current status. So we add a constant to the Stage class called PLAY_HEIGHT that contains the height of the playing area:


1     /**
2      * Curso B?sico de desarrollo de Juegos en Java - Invaders
3      * 
4      * (c) 2004 Planetalia S.L. - Todos los derechos reservados. Prohibida su reproducci?n
5      * 
6      * http://www.planetalia.com
7      * 
8      */
9     package version21;
10    
11    import java.awt.image.ImageObserver;
12    
13    public interface Stage extends ImageObserver {
14      public static final int WIDTH=640;
15      public static final int HEIGHT=480;
16 public static final int PLAY_HEIGHT = 400;
17 public static final int SPEED=10; 18 public SpriteCache getSpriteCache(); 19 public void addActor(Actor a); 20 } 21

The biggest change will take place in the Invaders class, where we must add the four methods for drawing each part of the status:


1     package version21;
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.Font;
16    import java.awt.Graphics2D;
17    import java.awt.Rectangle;
18    import java.awt.event.KeyEvent;
19    import java.awt.event.KeyListener;
20    import java.awt.event.WindowAdapter;
21    import java.awt.event.WindowEvent;
22    import java.awt.image.BufferStrategy;
23    import java.awt.image.BufferedImage;
24    import java.util.ArrayList;
25    
26    import javax.swing.JFrame;
27    import javax.swing.JPanel;
28    
29    public class Invaders extends Canvas implements Stage, KeyListener {
30      
31      private BufferStrategy strategy;
32      private long usedTime;
33      
34      private SpriteCache spriteCache;
35      private ArrayList actors; 
36      private Player player;
37      
38      public Invaders() {
39        spriteCache = new SpriteCache();
40        
41      
42        JFrame ventana = new JFrame("Invaders");
43        JPanel panel = (JPanel)ventana.getContentPane();
44        setBounds(0,0,Stage.WIDTH,Stage.HEIGHT);
45        panel.setPreferredSize(new Dimension(Stage.WIDTH,Stage.HEIGHT));
46        panel.setLayout(null);
47        panel.add(this);
48        ventana.setBounds(0,0,Stage.WIDTH,Stage.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        addKeyListener(this);
60      }
61      
62      public void initWorld() {
63        actors = new ArrayList();
64        for (int i = 0; i < 10; i++){
65          Monster m = new Monster(this);
66          m.setX( (int)(Math.random()*Stage.WIDTH) );
67          m.setY( i*20 );
68          m.setVx( (int)(Math.random()*20-10) );
69          
70          actors.add(m);
71        }
72        
73        player = new Player(this);
74        player.setX(Stage.WIDTH/2);
75        player.setY(Stage.PLAY_HEIGHT - 2*player.getHeight());
76      }
77      
78      public void addActor(Actor a) {
79        actors.add(a);
80      } 
81      
82      public void updateWorld() {
83        int i = 0;
84        while (i < actors.size()) {
85          Actor m = (Actor)actors.get(i);
86          if (m.isMarkedForRemoval()) {
87            actors.remove(i);
88          } else {
89            m.act();
90            i++;
91          }
92        }
93        player.act();
94      }
95      
96      public void checkCollisions() {
97        Rectangle playerBounds = player.getBounds();
98        for (int i = 0; i < actors.size(); i++) {
99          Actor a1 = (Actor)actors.get(i);
100         Rectangle r1 = a1.getBounds();
101         if (r1.intersects(playerBounds)) {
102           player.collision(a1);
103           a1.collision(player);
104         }
105         for (int j = i+1; j < actors.size(); j++) {
106           Actor a2 = (Actor)actors.get(j);
107           Rectangle r2 = a2.getBounds();
108           if (r1.intersects(r2)) {
109             a1.collision(a2);
110             a2.collision(a1);
111           }
112         }
113       }
114     }
115     
116 public void paintShields(Graphics2D g) { 117 g.setPaint(Color.red); 118 g.fillRect(280,Stage.PLAY_HEIGHT,Player.MAX_SHIELDS,30); 119 g.setPaint(Color.blue); 120 g.fillRect(280+Player.MAX_SHIELDS-player.getShields(),Stage.PLAY_HEIGHT,player.getShields(),30); 121 g.setFont(new Font("Arial",Font.BOLD,20)); 122 g.setPaint(Color.green); 123 g.drawString("Shields",170,Stage.PLAY_HEIGHT+20); 124 125 } 126 127 public void paintScore(Graphics2D g) { 128 g.setFont(new Font("Arial",Font.BOLD,20)); 129 g.setPaint(Color.green); 130 g.drawString("Score:",20,Stage.PLAY_HEIGHT + 20); 131 g.setPaint(Color.red); 132 g.drawString(player.getScore()+"",100,Stage.PLAY_HEIGHT + 20); 133 } 134 135 public void paintAmmo(Graphics2D g) { 136 int xBase = 280+Player.MAX_SHIELDS+10; 137 for (int i = 0; i < player.getClusterBombs();i++) { 138 BufferedImage bomb = spriteCache.getSprite("bombUL.gif"); 139 g.drawImage( bomb ,xBase+i*bomb.getWidth(),Stage.PLAY_HEIGHT,this); 140 } 141 } 142 143 public void paintfps(Graphics2D g) { 144 g.setFont( new Font("Arial",Font.BOLD,12)); 145 g.setColor(Color.white); 146 if (usedTime > 0) 147 g.drawString(String.valueOf(1000/usedTime)+" fps",Stage.WIDTH-50,Stage.PLAY_HEIGHT); 148 else 149 g.drawString("--- fps",Stage.WIDTH-50,Stage.PLAY_HEIGHT); 150 } 151 152 153 public void paintStatus(Graphics2D g) { 154 paintScore(g); 155 paintShields(g); 156 paintAmmo(g); 157 paintfps(g); 158 }
159 160 public void paintWorld() { 161 Graphics2D g = (Graphics2D)strategy.getDrawGraphics(); 162 g.setColor(Color.black); 163 g.fillRect(0,0,getWidth(),getHeight()); 164 for (int i = 0; i < actors.size(); i++) { 165 Actor m = (Actor)actors.get(i); 166 m.paint(g); 167 } 168 player.paint(g); 169 170
171 paintStatus(g);
172 strategy.show(); 173 } 174 175 public SpriteCache getSpriteCache() { 176 return spriteCache; 177 } 178 179 public void keyPressed(KeyEvent e) { 180 player.keyPressed(e); 181 } 182 183 public void keyReleased(KeyEvent e) { 184 player.keyReleased(e); 185 } 186 public void keyTyped(KeyEvent e) {} 187 188 public void game() { 189 usedTime=1000; 190 initWorld(); 191 while (isVisible()) { 192 long startTime = System.currentTimeMillis(); 193 updateWorld(); 194 checkCollisions(); 195 paintWorld(); 196 usedTime = System.currentTimeMillis()-startTime; 197 try { 198 Thread.sleep(SPEED); 199 } catch (InterruptedException e) {} 200 } 201 } 202 203 public static void main(String[] args) { 204 Invaders inv = new Invaders(); 205 inv.game(); 206 } 207 } 208

The result is:

Space Invaders Tutorial in Java



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


Full list of Java source files for this step

Actor.java Bomb.java Bullet.java Invaders.java
Monster.java Player.java SpriteCache.java Stage.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 - Collision detection Current Page - 21 - Status   Next Page - Score
  Return to the index of free Java tutorials  

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