import java.awt.*; import java.applet.Applet; import java.util.Random; public class Roasteroids extends Applet implements CollisionHandler { Panel topPanel, bottomPanel; Label scoreLabel, shipsLabel, copyright; Button startButton; int score, ships, level; int rocksToGo; boolean gameRunning, inHyperspace; SpriteWorld world; Sequence bigRoastSeq, medRoastSeq, smallRoastSeq, shipSeq, boomSeq; ShipSprite ship; Image shotImg; int shotLaunchX, shotLaunchY; MediaTracker appletTracker; int nextFreebie; final static float PI = (float) Math.PI; final static float ONEPOINTFIVEPI = (float) (1.5D * Math.PI); final static float TWOPI = (float) (2.0D * Math.PI); final static float THREEPI = (float) (3.0D * Math.PI); final static float FOURPI = (float) (4.0D * Math.PI); final static int START_SHIPS = 3; final static int FREEBIE_INTERVAL = 5000; final static int ROT_CLOCKWISE = (int)'x'; final static int ROT_COUNTERCLOCKWISE = (int)'z'; final static int THRUST = (int)'m'; final static int FIRE = (int)','; final static int HYPERSPACE = (int)'.'; Random rand = new Random(); public final String getAppletInfo() { return ("(c) 1997 Chris Adamson, plucky@mindspring.com, http://www.mindspring.com/~plucky/"); } public final void init() { world = new SpriteWorld (this); world.setBackground (Color.black); doLayout(); getImages(); gameRunning = false; startButton.setLabel ("Start"); world.start(); } // init public final void start() { this.showStatus ("z/x rotate m thrusts , fires . warps"); } // start protected final void getImages() { shotImg = getImage (getDocumentBase(), "images/shot0.gif"); appletTracker = new MediaTracker(this); appletTracker.addImage (shotImg, 2); bigRoastSeq = new Sequence ("images/lroaster", 16, this); medRoastSeq = new Sequence ("images/mroaster", 16, this); smallRoastSeq = new Sequence ("images/sroaster", 16, this); shipSeq = new Sequence ("images/ship", 36, this); boomSeq = new Sequence ("images/boom", 10, this); try { appletTracker.waitForID (2); } catch (InterruptedException e) { } shotLaunchX = shipSeq.imageAt(0).getWidth(this) / 2; shotLaunchY = shipSeq.imageAt(0).getHeight(this) / 2; } // getImages public void stop() { super.stop(); world.stop(); } // stop private final void startGame() { score = 0; ships = START_SHIPS; nextFreebie = FREEBIE_INTERVAL; scoreLabel.setText (Integer.toString (score)); shipsLabel.setText (Integer.toString (ships)); level = 1; ship = new ShipSprite (shipSeq, world, world.getWidth() / 2, world.getHeight() / 2, PI, 0, PI); inHyperspace = false; world.add (ship); gameRunning = true; } // startGame private final void startLevel () { rocksToGo = (level + 3) * 7; // how many hits until level ends for (int counter = 0; counter < level + 3; counter++) { if ((rand.nextInt() % 2) == 0) { world.add ( new AnimatedSprite (bigRoastSeq, world, 0 - bigRoastSeq.imageAt(0).getWidth(this), rand.nextInt() % world.getHeight(), rand.nextInt() % PI + PI, 70f, 5, true, true)); } else { world.add ( new AnimatedSprite (bigRoastSeq, world, rand.nextInt() % world.getWidth(), 0 - bigRoastSeq.imageAt(0).getHeight(this), rand.nextInt() % PI + PI, 70f, 5, false, true)); } // if-else that picks either forwards or backwards rotation } // for } //start Level private final void doLayout() { this.setBackground (Color.black); this.setForeground (Color.white); topPanel = new Panel(); bottomPanel = new Panel(); startButton = new Button ("Loading..."); scoreLabel = new Label ("0", Label.LEFT); shipsLabel = new Label (Integer.toString (START_SHIPS), Label.LEFT); copyright = new Label ("(c)1997 Chris Adamson"); topPanel.setLayout (new GridLayout (1, 4, 0, 0)); bottomPanel.setLayout (new GridLayout (1, 2, 0, 0)); topPanel.add (new Label ("Score: ", Label.RIGHT)); topPanel.add (scoreLabel); topPanel.add (new Label ("Ships: ", Label.RIGHT)); topPanel.add (shipsLabel); bottomPanel.add (copyright); bottomPanel.add (startButton); this.setLayout (new BorderLayout() ); this.add ("North", topPanel); this.add ("South", bottomPanel); this.add ("Center", world); this.validate(); } //do Layout public final void collision (HardlySprite sprite1, byte flags) { if (flags == CollisionHandler.EAST) { sprite1.setX (0 - sprite1.getWidth()); } if (flags == CollisionHandler.SOUTH) { sprite1.setY (0 - sprite1.getHeight()); } if (flags == CollisionHandler.WEST) { sprite1.setX (world.getWidth()); } if (flags == CollisionHandler.NORTH) { sprite1.setY (world.getHeight()); } } // collision with edge of screen public final boolean collision (HardlySprite sprite1, HardlySprite sprite2) { if ((sprite1 instanceof BoomSprite) || (sprite2 instanceof BoomSprite)) { return true; } else if ((sprite1 instanceof ShotSprite) && (sprite2 instanceof AnimatedSprite)) { breakRock ((ShotSprite) sprite1, (AnimatedSprite) sprite2); world.remove (sprite1); return false; } else if ((sprite1 instanceof AnimatedSprite) && (sprite2 instanceof ShotSprite)) { breakRock ((ShotSprite) sprite2, (AnimatedSprite) sprite1); world.remove (sprite2); return false; } else if (((sprite1 instanceof AnimatedSprite) && (sprite2 instanceof ShipSprite)) || ((sprite1 instanceof ShipSprite) && (sprite2 instanceof AnimatedSprite))) { playerDies(); return true; } else { return false; }// if-else-else } // two-sprite collision private final void breakRock (ShotSprite shot, AnimatedSprite victim) { int impactX, impactY; impactX = (int) shot.getX(); impactY = (int) shot.getY(); world.add (new BoomSprite (boomSeq, world, impactX, impactY, 7)); rocksToGo--; if (victim.getSequence() == smallRoastSeq) { addToScore (100); world.remove(victim); if (rocksToGo == 0) { advanceLevel(); } return; } else if (victim.getSequence() == medRoastSeq) { addToScore (50); world.add (new AnimatedSprite (smallRoastSeq, world, impactX, impactY, rand.nextInt() % TWOPI, rand.nextFloat() * 10 + 70f, rand.nextInt() % 3 + 7, true, true)); world.add (new AnimatedSprite (smallRoastSeq, world, impactX, impactY, rand.nextInt() % TWOPI, rand.nextFloat() * 10 + 70f, rand.nextInt() % 3 + 7, false, true)); world.remove(victim); return; } else if (victim.getSequence() == bigRoastSeq) { addToScore (20); world.add (new AnimatedSprite (medRoastSeq, world, impactX, impactY, rand.nextInt() % TWOPI, rand.nextFloat() * 10 + 80f, rand.nextInt() % 5 + 9, true, true)); world.add (new AnimatedSprite (medRoastSeq, world, impactX, impactY, rand.nextInt() % TWOPI, rand.nextFloat() * 10 + 80f, rand.nextInt() % 5 + 9, false, true)); world.remove(victim); return; } } // breakRock private final void playerDies() { int boomX, boomY; if (!ship.isExploding()) { boomX = (int) ship.getX(); boomY = (int) ship.getY(); world.add (new BoomSprite (boomSeq, world, boomX, boomY, 5)); ship.explode(); ships--; shipsLabel.setText (Integer.toString (ships)); if (ships == 0) { endGame(boomX, boomY); } } // if ship not already exploding } //playerDies private final void endGame (int boomX, int boomY) { world.removeAll(); world.clearScreen(); world.add (new BoomSprite (boomSeq, world, boomX, boomY, 5)); ship = null; gameRunning = false; } //endGame public final boolean keyDown(Event evt, int key) { try { if (key == ROT_COUNTERCLOCKWISE) { ship.rotateCounterclockwise(); return true; } else if (key == ROT_CLOCKWISE) { ship.rotateClockwise(); return true; } else if (key == THRUST) { ship.thrust(); return true; } else if (key == HYPERSPACE) { hyperspace(); return true; } else { return super.keyDown (evt, key);} } catch (NullPointerException e) { } // ignore NPE if keyUp before ship created return super.keyDown (evt, key); // this will never be executed, but compiler doesn't like where I put my try-catch } //keyDown public final boolean keyUp (Event evt, int key) { try { if ((key == ROT_COUNTERCLOCKWISE) || (key == ROT_CLOCKWISE)) { ship.stopRotating(); return true; } else if (key == FIRE) { if (ship.isExploding()) { return true; } fire(); return true; } else if (key == THRUST) { ship.stopThrusting(); return true; } else if (key == HYPERSPACE) { inHyperspace = false; return true; } else { return super.keyUp (evt, key); } } catch (NullPointerException e) { } // ignore NPE if keyUp before ship created return super.keyDown (evt, key); // this will never be executed, but compiler doesn't like where I put my try-catch } //keyUp protected void addToScore (int newPoints) { score += newPoints; scoreLabel.setText (Integer.toString(score)); if (score > nextFreebie) { ships++; shipsLabel.setText (Integer.toString (ships)); nextFreebie += FREEBIE_INTERVAL; } } // addToScore public final boolean action (Event e, Object arg) { if (e.target == startButton) { if (!gameRunning) { startGame(); startLevel(); return true; } else { // handle pause button return true; } } else { return super.action (e, arg); }//if-else }// action private final void fire() { world.add (new ShotSprite (shotImg, world, (int) (ship.getX() + shotLaunchX), (int) (ship.getY() + shotLaunchY), ship.getPointing(), 250)); } private final void hyperspace() { if (!ship.isExploding() && !inHyperspace) { inHyperspace = true; world.remove(ship); ship.setX (rand.nextFloat() * world.getWidth()); ship.setY (rand.nextFloat() * world.getHeight()); world.add (ship); } } private final void advanceLevel () { level++; startLevel(); } //advanceLevel } // Roasteroids