home *** CD-ROM | disk | FTP | other *** search
Java Source | 1996-10-03 | 15.7 KB | 838 lines |
- /* MissileCommando.java - based on the arcade game Missile Command. */
-
- /*
- * Copyright (C) 1996 Mark Boyns <boyns@sdsu.edu>
- *
- * Missile Commando II
- * <URL:http://www.sdsu.edu/~boyns/java/mcii/>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
- import java.applet.Applet;
- import java.applet.AudioClip;
- import java.util.*;
- import java.awt.*;
-
- public
- class MissileCommando extends java.applet.Applet implements Runnable
- {
- final String version = "MCII 1.1";
- final int worldWidth = 500;
- final int worldHeight = 300;
- final int scoreHeight = 25;
- final int controlsHeight = 50;
- final int screenWidth = worldWidth;
- final int screenHeight = worldHeight + scoreHeight + controlsHeight;
-
- final int baseWidth = 64;
- final int baseHeight = 32;
- final int baseGap = 30;
- final int maxBases = 5;
-
- final int missilePoints = 75;
- final int mrvPoints = 150;
- final int bombPoints = 0;
- final int extraShotPoints = 10;
- final int extraBasePoints = 50;
- final int rebuildBasePoints = 10000;
-
- AudioClip missileSound = null;
- AudioClip missileExplosionSound = null;
- AudioClip mrvExplosionSound = null;
- AudioClip baseExplosionSound = null;
- AudioClip bombSound = null;
-
- boolean playing = false;
- boolean readyToPlay = false;
- boolean clearScreen = false;
- boolean paused = false;
- boolean soundEnabled = true;
-
- Thread thread = null;
- GameObjectMover mover = null;
-
- Controls controls;
-
- Vector bases;
- Vector missiles;
- Vector shots;
- Vector mrvs;
- Vector explosions;
- Vector bombs;
- Vector bombDebris;
-
- int score = 0;
- int extraBaseScore = 0;
- int level = 0;
-
- int shotCount = 0;
- int missileCount = 0;
- int missileSpeed = 0;
- int missileDelay = 0;
- int mrvSpeed = 0;
- int bombSpeed = 0;
-
- Color skyColor = new Color (148, 198, 231);
- Graphics world = null;
-
- MediaTracker tracker;
- Image baseImage;
- Image mrvImage;
- Image bombImage;
-
- Font font;
- FontMetrics fontMetrics;
-
- String screenMessage;
-
- public
- void init ()
- {
- int i, x;
-
- font = new Font ("TimesRoman", Font.BOLD, 20);
- fontMetrics = getFontMetrics (font);
- setFont (font);
-
- tracker = new MediaTracker (this);
- baseImage = getImage (getDocumentBase (), "images/base.gif");
- tracker.addImage (baseImage, 1);
- mrvImage = getImage (getDocumentBase (), "images/mrv.gif");
- tracker.addImage (mrvImage, 1);
- bombImage = getImage (getDocumentBase (), "images/bomb.gif");
- tracker.addImage (bombImage, 1);
-
- /* Load all the sounds. */
- missileSound = getAudioClip (getDocumentBase (), "sounds/Rocket.au");
- missileExplosionSound = getAudioClip (getDocumentBase (), "sounds/Oomph.au");
- mrvExplosionSound = getAudioClip (getDocumentBase (), "sounds/Oomph.au");
- baseExplosionSound = getAudioClip (getDocumentBase (), "sounds/Explosion-2.au");
- bombSound = getAudioClip (getDocumentBase (), "sounds/ship_alarm.au");
-
- setBackground (Color.white);
-
- setLayout (new BorderLayout ());
- controls = new Controls (this);
- add ("South", controls);
-
- resize (screenWidth, screenHeight);
-
- /* Start the game! */
- thread = new Thread (this);
- thread.start ();
- }
-
- public
- void start ()
- {
- if (thread == null)
- {
- thread = new Thread (this);
- thread.start ();
- }
- }
-
- public
- void stop ()
- {
- if (thread != null && thread.isAlive ())
- {
- thread.stop ();
- thread = null;
- }
- if (mover != null && mover.isAlive ())
- {
- mover.stop ();
- mover = null;
- }
- }
-
- public
- boolean mouseDown (Event e, int x, int y)
- {
- if (playing)
- {
- createShot (x, y - scoreHeight);
- }
- return true;
- }
-
- void startGame ()
- {
- readyToPlay = true;
- }
-
- void quitGame ()
- {
- playing = false;
- }
-
- void resetScore ()
- {
- clearScreen = true;
-
- score = 0;
- extraBaseScore = 0;
- level = 0;
-
- message (null);
- }
-
- void resetGame ()
- {
- clearScreen = true;
-
- missiles = new Vector (100);
- shots = new Vector (100);
- mrvs = new Vector (100);
- explosions = new Vector (100);
- bombs = new Vector (100);
- bombDebris = new Vector (100);
-
- //controls.playButton.setLabel ("Start");
- //controls.suspendButton.setLabel ("Suspend");
- //controls.soundButton.setLabel ("Sound Off");
-
- createBases ();
- message (null);
- }
-
- void suspendGame ()
- {
- if (thread != null && playing)
- {
- thread.suspend ();
- if (mover != null && mover.isAlive ())
- {
- mover.suspend ();
- }
- paused = true;
- clearScreen = true;
- repaint ();
- }
- }
-
- void resumeGame ()
- {
- if (thread != null && playing)
- {
- thread.resume ();
- if (mover != null && mover.isAlive ())
- {
- mover.resume ();
- }
- paused = false;
- clearScreen = true;
- }
- }
-
- void enableSound ()
- {
- soundEnabled = true;
- }
-
- void disableSound ()
- {
- soundEnabled = false;
- }
-
- public
- void run ()
- {
- showStatus ("Loading images...");
- tracker.checkAll (true);
- try
- {
- tracker.waitForAll ();
- }
- catch (Exception e)
- {
- return;
- }
- showStatus ("");
-
- resetGame ();
- resetScore ();
-
- for (;;)
- {
- if (!playing && readyToPlay)
- {
- resetGame ();
- resetScore ();
- playing = true;
- readyToPlay = false;
- }
-
- if (playing)
- {
- level++;
- }
- else if (level == 0)
- {
- level = 1;
- }
-
- /* Set the delay between missiles. */
- if (playing)
- {
- missileDelay = 2000 - ((level-1)*200);
- if (missileDelay < 500)
- {
- missileDelay = 500;
- }
- }
- else
- {
- missileDelay = 500;
- }
-
- /* Set the missile speed. */
- missileSpeed = 5;
-
- /* Set the MRV speed. */
- mrvSpeed = 6;
-
- /* Set the bomb speed. */
- bombSpeed = 4;
-
- /* Set the number of missiles to be fired. */
- missileCount = 5 + ((level-1) * 5);
-
- /* Set the maximum number of shots. */
- shotCount = missileCount * 2; // + missileCount/2;
-
- /* Display the new level message. */
- message ("Level " + level);
- try
- {
- Thread.sleep (3000);
- }
- catch (Exception e)
- {
- }
- message (null);
-
- /* Start the object mover thread to move all the
- game objects. */
- mover = new GameObjectMover (100, this);
- mover.start ();
-
- while (missileCount > 0)
- {
- /* Fire a missile. */
- int speed = missileSpeed;
- if (level > 1 && Math.random () > 0.75)
- {
- speed += (int) (Math.random () * missileSpeed);
- }
- createMissile (speed);
- missileCount--;
-
- /* Maybe create a mrv. */
- if (mrvs.size () < level)
- {
- double chance = Math.random ();
- if (chance > 0.70)
- {
- createMRV (mrvSpeed);
- }
- }
-
- /* Maybe drop a bomb. */
- if (level > 1 && bombs.size () < 2)
- {
- double chance = Math.random ();
- if (chance > 0.85)
- {
- createBomb (bombSpeed);
- }
- }
-
- if (!playing)
- {
- starWars ();
- }
-
- if (!playing && readyToPlay)
- {
- break;
- }
-
- try
- {
- Thread.sleep (missileDelay);
- }
- catch (Exception e)
- {
- }
- }
-
- if (!playing && readyToPlay)
- {
- mover.stop ();
- continue;
- }
-
- /* Wait for everything to disappear. */
- while (missiles.size () > 0
- || mrvs.size () > 0
- || explosions.size () > 0
- || bombs.size () > 0
- || bombDebris.size () > 0
- || shots.size () > 0)
- {
- if (!playing && readyToPlay)
- {
- break;
- }
- if (!playing && (missiles.size () > 0 || mrvs.size () > 0 || bombs.size () > 0))
- {
- starWars ();
- }
- try
- {
- Thread.sleep (500);
- }
- catch (Exception e)
- {
- }
- }
-
- /* Stop the object mover thread. */
- mover.stop ();
-
- /* Calculate bonus points. */
- int bonus = shotCount * extraShotPoints;
- bonus += countAliveBases () * extraBasePoints;
- incrementScore (bonus);
-
- if (playing)
- {
- /* Display the bonus points message. */
- message ("Bonus: " + bonus);
- try
- {
- Thread.sleep (2000);
- }
- catch (Exception e)
- {
- }
- message (null);
- }
-
- /* Possibly rebuild any destroyed bases. */
- rebuildBases ();
-
- /* The game is over when no bases are left. */
- if (countAliveBases () == 0)
- {
- playing = false;
-
- /* Destroy the world. */
- mover = new GameObjectMover (400, this);
- mover.start ();
- destroyWorld ();
- while (explosions.size () > 0)
- {
- try
- {
- Thread.sleep (500);
- }
- catch (Exception e)
- {
- }
- }
- mover.stop ();
-
- resetGame ();
- }
- }
- }
-
- void starWarsFireAt (Vector v)
- {
- int x, y;
- Enumeration objs = v.elements ();
- while (objs.hasMoreElements ())
- {
- GameObject o = (GameObject) objs.nextElement ();
- if (o instanceof Missile)
- {
- Missile m = (Missile) o;
- x = (int) m.x;
- y = (int) m.y;
- }
- else if (o instanceof MRV)
- {
- MRV m = (MRV) o;
- x = m.x;
- y = m.y;
- }
- else if (o instanceof Bomb)
- {
- Bomb b = (Bomb) o;
- x = b.x;
- y = b.y;
- }
- else
- {
- x = worldWidth/2;
- y = worldHeight/2;
- }
-
- if (y > worldHeight/5)
- {
- int d;
- if (Math.random () > 0.5)
- {
- d = 1;
- }
- else
- {
- d = -1;
- }
- shots.addElement (new Shot (x+d*(int)(Math.random ()*40),
- y+d*(int)(Math.random ()*40),
- 60));
- }
- }
-
- }
-
- void starWars ()
- {
- starWarsFireAt (missiles);
- starWarsFireAt (mrvs);
- starWarsFireAt (bombs);
- }
-
- void createShot (int x, int y)
- {
- if (shotCount > 0)
- {
- shots.addElement (new Shot (x, y, 60));
- shotCount--;
- }
- }
-
- void createMissile (int x1, int y1, int speed)
- {
- int x2 = baseGap + (int) (Math.random () * (worldWidth - baseGap));
- int y2 = worldHeight - 1;
-
- if (soundEnabled && missileSound != null && playing)
- {
- missileSound.play ();
- }
-
- missiles.addElement (new Missile (x1, y1, x2, y2, speed));
- }
-
- void createMissile (int speed)
- {
- int x1 = (int) (Math.random () * worldWidth);
- int y1 = 1;
- createMissile (x1, y1, speed);
- }
-
- void destroyMissile (Missile m)
- {
- if (soundEnabled && missileExplosionSound != null && playing)
- {
- missileExplosionSound.play ();
- }
- m.explode ();
- createExplosion ((int)m.x, (int)m.y, 20);
- incrementScore (missilePoints);
- }
-
- void createMRV (int speed)
- {
- int x1 = (int) (Math.random () * worldWidth);
- int y1 = 1;
- int y2 = worldHeight - 1;
-
- mrvs.addElement (new MRV (x1, y1, y2, speed, mrvImage, this));
- }
-
- void destroyMRV (MRV m)
- {
- if (soundEnabled && mrvExplosionSound != null && playing)
- {
- mrvExplosionSound.play ();
- }
- m.explode ();
- createExplosion (m.x, m.y, 10);
- incrementScore (mrvPoints);
- }
-
- void createBomb (int speed)
- {
- if (soundEnabled && bombSound != null && playing)
- {
- bombSound.play ();
- }
-
- int x1 = (int) (Math.random () * worldWidth);
- int y1 = 1;
- int y2 = worldHeight - 1;
-
- bombs.addElement (new Bomb (x1, y1, x1, y2, speed, bombImage, this));
- }
-
- void destroyBomb (Bomb b)
- {
- b.explode ();
- createBombDebris (b.x, b.y);
- }
-
- void createBombDebris (int x, int y)
- {
- bombDebris.addElement (new BombDebris (x, y, 200));
- }
-
- void createBases ()
- {
- bases = new Vector (maxBases);
- for (int i = 0, x = baseGap; i < maxBases; i++)
- {
- bases.addElement (new Base (x, worldHeight - baseHeight,
- baseWidth, baseHeight, baseImage, this));
- x += baseWidth + baseGap;
- }
- }
-
- int countAliveBases ()
- {
- int count = 0;
- for (int i = 0; i < maxBases; i++)
- {
- Base b = (Base) bases.elementAt (i);
- if (b.alive ())
- {
- count++;
- }
- }
- return count;
- }
-
- void destroyBase (Base b, Missile m)
- {
- if (soundEnabled && baseExplosionSound != null && playing)
- {
- baseExplosionSound.play ();
- }
- m.explode ();
- b.explode ();
- createExplosion ((int)m.x, (int)m.y, 100);
- }
-
- void destroyBase (Base b, MRV m)
- {
- if (soundEnabled && baseExplosionSound != null && playing)
- {
- baseExplosionSound.play ();
- }
- m.explode ();
- b.explode ();
- createExplosion (m.x, m.y, 100);
- }
-
- void destroyBase (Base b, BombDebris debris)
- {
- if (soundEnabled && baseExplosionSound != null && playing)
- {
- baseExplosionSound.play ();
- }
- b.explode ();
- createExplosion (b.x + b.w/2,
- b.y + b.h/2, 100);
- }
-
- void rebuildBases ()
- {
- int order[] = new int[maxBases];
- int i;
-
- for (i = 0; i < order.length; i++)
- {
- order[i] = -1;
- }
-
- for (i = 0; i < maxBases; i++)
- {
- int n = (int) (Math.random () * maxBases);
- while (order[n] != -1)
- {
- n++;
- if (n == maxBases)
- {
- n = 0;
- }
- }
- order[n] = i;
- }
-
- for (i = 0; i < maxBases; i++)
- {
- Base b = (Base) bases.elementAt (order[i]);
- if (! b.alive ())
- {
- if (extraBaseScore >= rebuildBasePoints)
- {
- extraBaseScore -= rebuildBasePoints;
- b.rebuild ();
- }
- }
- }
- }
-
- void createExplosion (int x, int y, int size)
- {
- explosions.addElement (new Explosion (x, y, size));
- }
-
- void incrementScore (int points)
- {
- if (playing)
- {
- score += points;
- extraBaseScore += points;
- }
- }
-
- void destroyWorld ()
- {
- for (int i = 0; i < 10; i++)
- {
- int x = (int)(Math.random () * worldWidth);
- int y = (int)(Math.random () * worldHeight);
- createExplosion (x, y, 100);
- }
- }
-
- public
- void update (Graphics g)
- {
- paint (g);
- }
-
- void paintGameObjects (Vector objs, Graphics g)
- {
- if (objs == null)
- {
- return;
- }
-
- Enumeration e = objs.elements ();
- while (e.hasMoreElements ())
- {
- GameObject o = (GameObject) e.nextElement ();
- o.paint (g);
- }
- }
-
- void message (String message)
- {
- if (message != null)
- {
- screenMessage = message;
- }
- else
- {
- screenMessage = null;
- clearScreen = true;
- }
- repaint ();
- }
-
- void paintMessage (String message, Graphics g)
- {
- int h = fontMetrics.getHeight ();
- int w = fontMetrics.stringWidth (message);
- g.setColor (Color.black);
- g.drawString (message, worldWidth/2 - w/2, worldHeight/2);
- }
-
- void paintStatus (Graphics g)
- {
- StringBuffer s = new StringBuffer ();
- s.append ("Score: ");
- s.append (score);
- s.append (" Level: ");
- s.append (level);
- s.append (" Shots: ");
- s.append (shotCount);
-
- int h = fontMetrics.getHeight ();
- int w = fontMetrics.stringWidth (s.toString ());
- int n = screenWidth/2 - w/2;
-
- g.setColor (Color.white);
- g.fillRect (0, 0, screenWidth, scoreHeight);
-
- g.setColor (Color.black);
- g.drawString (s.toString (), n, h);
-
- w = fontMetrics.stringWidth (version);
- g.drawString (version, screenWidth - w, h);
- }
-
- public
- void paint (Graphics g)
- {
- if (world == null)
- {
- world = g.create (0, scoreHeight, worldWidth, worldHeight);
- }
-
- if (clearScreen)
- {
- g.setColor (Color.white);
- g.fillRect (0, 0, worldWidth, worldHeight);
-
- world.setColor (skyColor);
- world.fillRect (0, 0, worldWidth, worldHeight);
- clearScreen = false;
- }
-
- if (paused)
- {
- paintMessage ("PAUSED", world);
- return;
- }
-
- paintStatus (g);
- paintGameObjects (mrvs, world);
- paintGameObjects (missiles, world);
- paintGameObjects (bombs, world);
- paintGameObjects (bases, world);
- paintGameObjects (shots, world);
- paintGameObjects (explosions, world);
- paintGameObjects (bombDebris, world);
-
- if (!playing)
- {
- paintMessage ("GAME OVER", world);
- }
- else if (screenMessage != null)
- {
- paintMessage (screenMessage, world);
- }
- }
- }
-