Training and Consulting | ||
| Home |
| Previous Page - Controlling the player | Current Page - 18 - Shots | Next Page - More shooting - Cluster bombs |
| Return to the index of free Java tutorials |
ShotsOk, it's finally time to add some violence to our - so far - pacific game. We will implement the ability of the player to shoot missiles. For now we will concentrate only on the missiles, their movement, how they appear and disappear and will leave their effects (killing monsters) for a later step. Our missiles will follow these premises
From the point of view of the game, shots are merely actors. The new thing about missiles is that they appear and disappear dynamically based on factors that are outside the control of the main game loop. For example, the main game loop does not control when the player chooses to fire a missile. However, when this happens, a new actor must be created and added to the global list of actors. The Player class gets the keyboard event, but the global actor list is responsability of the Invaders class. A possible solution is giving the stage ability to add actors on the fly:
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 version18; 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 SPEED=10; 17 public SpriteCache getSpriteCache(); Removing actors, however, is not as simple as merely creating a new method removeActor(...) in Stage. The reason is that this removal method might get called from a differen thread - for example as a result of a keyboard event. But it could happen that at the same time we are trying to remove an actor, the main game loop (and the main thread) are iterating the list of actors doing something. Removing an actor in the middle of the iteration - without these loops knowing it could cause problems, like for example the act() method of the actor following the removed one not being called, or calling the act() method of the actor we've just removed, or painting it again even though it has just been removed One possible solution is to synchronize all accesses to the global list of actors, but we would be creating a big bottleneck and we want to keep the game as fast as possible A second option is creating a tag inside the Actor class that acts as a "marker for removal". Whenever someone in any thread wants to remove an actor, it simply "marks" it "for removal". The main loop can afterwards check this mark and remove the actor from the list of actors without creating concurrency problems : This new concept requires a rewrite of the Actor class in the following way:
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 version18; 10 11 import java.awt.Graphics2D; 12 import java.awt.image.BufferedImage; 13 14 public class Actor { 15 protected int x,y; 16 protected int width, height; 17 protected String[] spriteNames; 18 protected int currentFrame; 19 protected int frameSpeed; 20 protected int t; 21 protected Stage stage; 22 protected SpriteCache spriteCache; 24 25 public Actor(Stage stage) { 26 this.stage = stage; 27 spriteCache = stage.getSpriteCache(); 28 currentFrame = 0; 29 frameSpeed = 1; 30 t=0; 31 } 32 And now the methods updateWorld() and addActor() become :
. . .
75 public void addActor(Actor a) {
76 actors.add(a);
77 }
78
79 public void updateWorld() {
80 int i = 0;
81 while (i < actors.size()) {
82 Actor m = (Actor)actors.get(i);
83 if (m.isMarkedForRemoval()) {
84 actors.remove(i);
85 } else {
86 m.act();
87 i++;
88 }
89 }
90 player.act();
91 }
. . .
Once that we have a robust system for removing actors, we can handle the missiles. For a missile we'll use the following image, called "disparo.gif":
Missiles, as they have their own behaviour, will need a new class to represent them. We'll call that class Bullet:
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 version18; 10 11 12 public class Bullet extends Actor { 13 protected static final int BULLET_SPEED=10; 14 15 public Bullet(Stage stage) { 16 super(stage); 17 setSpriteNames( new String[] {"misil.gif"}); 18 } 19 20 public void act() { 21 super.act(); 22 y-=BULLET_SPEED; 23 if (y < 0) 24 remove(); 25 } 26 } 27 The act() method of a missile moves it upwards and removes it (or more correctly, marks it for removal) whenever it reaches the upper limit of the screen Finally, the only thing left is adding a new key to the Player class that will fire a missile when pressed:
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 version18; 10 11 import java.awt.event.KeyEvent; 12 13 public class Player extends Actor { 14 protected static final int PLAYER_SPEED = 4; 15 protected int vx; 16 protected int vy; 17 private boolean up,down,left,right; 18 19 20 public Player(Stage stage) { 21 super(stage); 22 setSpriteNames( new String[] {"nave.gif"}); 23 } 24 25 public void act() { 26 super.act(); 27 x+=vx; 28 y+=vy; 29 if (x < 0 || x > Stage.WIDTH) 30 vx = -vx; 31 if (y < 0 || y > Stage.HEIGHT) 32 vy = -vy; 33 } 34 35 public int getVx() { return vx; } 36 public void setVx(int i) {vx = i; } 37 public int getVy() { return vy; } 38 public void setVy(int i) {vy = i; } 39 40 41 protected void updateSpeed() { 42 vx=0;vy=0; 43 if (down) vy = PLAYER_SPEED; 44 if (up) vy = -PLAYER_SPEED; 45 if (left) vx = -PLAYER_SPEED; 46 if (right) vx = PLAYER_SPEED; 47 } 48 49 public void keyReleased(KeyEvent e) { 50 switch (e.getKeyCode()) { 51 case KeyEvent.VK_DOWN : down = false;break; 52 case KeyEvent.VK_UP : up = false; break; 53 case KeyEvent.VK_LEFT : left = false; break; 54 case KeyEvent.VK_RIGHT : right = false;break; 55 } 56 updateSpeed(); 57 } 58 59 public void keyPressed(KeyEvent e) { 60 switch (e.getKeyCode()) { 61 case KeyEvent.VK_UP : up = true; break; 62 case KeyEvent.VK_LEFT : left = true; break; 63 case KeyEvent.VK_RIGHT : right = true; break; 64 case KeyEvent.VK_DOWN : down = true;break; 66 } 67 updateSpeed(); 68 } 69
|
||||||||||||||||||||||||||||||||
Do you want to be notified when new tutorials or lessons are published? Press here
| Bullet.java | Stage.java | Monster.java | SpriteCache.java |
| Invaders.java | Actor.java | Player.java |
| Previous Page - Controlling the player | Current Page - 18 - Shots | Next Page - More shooting - Cluster bombs |
| Return to the index of free Java tutorials |
(c) 2004 Planetalia S.L. All rights reserved. Unauthorized reproduction and/or mirroring is not permitted