Missile Commando

download Missile Commando

of 47

Transcript of Missile Commando

  • 8/12/2019 Missile Commando

    1/47

    Missile Commando

    CODE:

    package Ochoa.cpe;

    /* MissileCommando.java - based on the arcade game Missile Command. */

    /*

    * Copyright (C) 1995 Mark Boyns

    *

    * MissileCommando

    *

    *

    * 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.

    *

  • 8/12/2019 Missile Commando

    2/47

    * 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.*;

    import java.awt.*;

    import java.util.Enumeration;

    import java.util.Vector;

    /* Abstract class used for moving objects, etc. */

    abstract class Thing extends Thread

    {

    MissileCommando parent;

    public int X;

    public int Y;

    Color color;

    abstract void paint (Graphics g); /* paint the object */

    abstract void erase (Graphics g); /* erase the object */

    abstract boolean hit (Missile m); /* did this missile hit the object? */

    abstract void explode (); /* explode the object */

  • 8/12/2019 Missile Commando

    3/47

    }

    /* A simple rectangular base. This object just sits around waiting to

    explode. */

    class Base extends Thing

    {

    private int W = 0;

    private int H = 0;

    Base (MissileCommando parent, Color color, int x, int y, int w, int h)

    {

    this.parent = parent;

    X = x;

    Y = y;

    this.color = color;

    W = w;

    H = h;

    start ();

    }

    public void run ()

  • 8/12/2019 Missile Commando

    4/47

    {

    Thread.currentThread().setPriority (Thread.MIN_PRIORITY);

    waitToDie ();

    }

    public synchronized void waitToDie ()

    {

    try

    {

    wait ();

    }

    catch (InterruptedException e)

    {

    }

    }

    public synchronized void timeToDie ()

    {

    notify ();

    }

    public boolean hit (Missile m)

    {

    return (m.X >= X && m.X

  • 8/12/2019 Missile Commando

    5/47

    && m.Y >= Y && m.Y

  • 8/12/2019 Missile Commando

    6/47

    missile can randomly replicate itself into 3 missiles. */

    class Missile extends Thing

    {

    private boolean paintme = false;

    private int X1 = 0;

    private int Y1 = 0;

    private int X2 = 0;

    private int Y2 = 0;

    private int V = 0;

    private float m = 0;

    private float b = 0;

    private float x = 0;

    private float y = 0;

    private boolean replicate = false;

    Missile (MissileCommando parent, Color color, int x1, int y1, int x2, int y2, int v)

    {

    this.parent = parent;

    X = X1;

    Y = Y1;

    this.color = color;

    X1 = x1;

    Y1 = y1;

  • 8/12/2019 Missile Commando

    7/47

    X2 = x2;

    Y2 = y2;

    V = v;

    start ();

    }

    public void run ()

    {

    Thread.currentThread().setPriority (Thread.MIN_PRIORITY);

    m = (float) (Y2 - Y1) / (X2 - X1);

    b = Y1 - (m*X1);

    x = X1;

    y = Y1;

    /* 10% chance this missile will replicate. */

    replicate = Math.random () > 0.90;

    if (replicate)

    {

    color = Color.magenta;

    }

    while (y

  • 8/12/2019 Missile Commando

    8/47

    {

    /* 25% chance this missile will replicate now. */

    if (replicate && y > Y1+5*V && Math.random () > 0.75)

    {

    for (int i = 0; i < 3; i++)

    {

    parent.createMissile (X, Y, V);

    }

    /* stop the current missile */

    break;

    }

    paintme = true;

    parent.repaint ();

    try

    {

    Thread.sleep (100);

    }

    catch (InterruptedException e)

    {

    }

    }

  • 8/12/2019 Missile Commando

    9/47

    paintme = true;

    parent.repaint ();

    }

    public boolean hit (Missile m)

    {

    return m.X == X && m.Y == Y;

    }

    public void explode ()

    {

    stop ();

    }

    public void paint (Graphics g)

    {

    if (paintme)

    {

    g.setColor (Color.lightGray);

    g.drawLine (X1, Y1, X, Y);

    y += V;

    x = (y - b) / m;

  • 8/12/2019 Missile Commando

    10/47

    X = (int)x;

    Y = (int)y;

    g.setColor (color);

    g.drawLine (X1, Y1, X, Y);

    paintme = false;

    }

    }

    public void erase (Graphics g)

    {

    g.setColor (Color.lightGray);

    g.drawLine (X1, Y1, X, Y);

    }

    }

    /* Generic explosion which draws a circle that grows and shrinks. The

    explosion is draw at X,Y and has a maximum size of S. */

    class Explosion extends Thing

    {

    private boolean paintme = false;

    private int S = 0;

  • 8/12/2019 Missile Commando

    11/47

  • 8/12/2019 Missile Commando

    12/47

    parent.repaint ();

    try

    {

    Thread.sleep (50);

    }

    catch (InterruptedException e)

    {

    }

    }

    while (size

  • 8/12/2019 Missile Commando

    13/47

    }

    }

    while (size >= 0);

    paintme = true;

    parent.repaint ();

    }

    public boolean hit (Missile m)

    {

    return (m.X >= (X - size/2) && m.X = (Y - size/2) && m.Y

  • 8/12/2019 Missile Commando

    14/47

    g.setColor (Color.lightGray);

    g.fillOval (X - size/2, Y - size/2, size, size);

    }

    size += scale;

    g.setColor (color);

    g.fillOval (X - size/2, Y - size/2, size, size);

    paintme = false;

    }

    }

    public void erase (Graphics g)

    {

    }

    }

    /* A shot explosion base on Explosion. */

    class ShotExplosion extends Explosion

    {

    ShotExplosion (MissileCommando parent, int x, int y)

    {

    super (parent, Color.black, x, y, 60);

  • 8/12/2019 Missile Commando

    15/47

  • 8/12/2019 Missile Commando

    16/47

    this.parent = parent;

    this.message = message;

    X = x;

    Y = y;

    this.blinks = blinks;

    this.delay = delay;

    color = Color.black;

    start ();

    }

    Message (MissileCommando parent, String message, int x, int y, int blinks)

    {

    this (parent, message, x, y, blinks, 500);

    }

    Message (MissileCommando parent, String message, int x, int y)

    {

    this (parent, message, x, y, 3, 500);

    }

    public void run ()

    {

    Thread.currentThread().setPriority (Thread.MIN_PRIORITY);

  • 8/12/2019 Missile Commando

    17/47

    for (blinkCount = 0; blinkCount < 2*blinks; blinkCount++)

    {

    parent.repaint ();

    try

    {

    Thread.sleep (delay);

    }

    catch (InterruptedException e)

    {

    }

    }

    parent.repaint ();

    }

    public void paint (Graphics g)

    {

    if ((blinkCount % 2) == 0)

    {

    g.setColor (color);

    }

    else

    {

  • 8/12/2019 Missile Commando

    18/47

    g.setColor (Color.lightGray);

    }

    g.drawString (message, X, Y);

    }

    public void erase (Graphics g)

    {

    g.setColor (Color.lightGray);

    g.drawString (message, X, Y);

    }

    public boolean hit (Missile m)

    {

    return false;

    }

    public void explode ()

    {

    }

    }

    /* Semaphore class used to synchronize threads. */

    class Semaphore

  • 8/12/2019 Missile Commando

    19/47

    {

    private boolean taken;

    Semaphore ()

    {

    taken = false;

    }

    Semaphore (boolean taken)

    {

    this.taken = taken;

    }

    public synchronized void take ()

    {

    while (taken)

    {

    try

    {

    wait ();

    }

    catch (Exception e)

    {

    }

  • 8/12/2019 Missile Commando

    20/47

    }

    taken = true;

    }

    public synchronized boolean peek ()

    {

    return taken;

    }

    public synchronized void give ()

    {

    taken = false;

    notify ();

    }

    }

    /* The main applet. */

    public class MissileCommando extends java.applet.Applet implements Runnable

    {

    /* Screen sizes. */

    private final int SCORE_WIDTH = 70;

    private final int WORLD_WIDTH = 430;

    private final int WORLD_HEIGHT = 300;

  • 8/12/2019 Missile Commando

    21/47

    /* Base parameters. */

    private final int BASES = 5;

    private final int BASE_SPACING = 30;

    private final int BASE_WIDTH = 50;

    private final int BASE_HEIGHT = 40;

    /* Points */

    private final int POINTS_MISSILE = 100;

    private final int POINTS_EXTRA_SHOTS = 50;

    private final int POINTS_BASE = 100;

    private final int POINTS_NEW_BASE = 5000;

    /* Limit the number of concurrent shots. */

    private final int MAX_SHOTS = 10;

    private int shots = 0;

    /* The sounds. */

    private AudioClip startSound = null;

    private AudioClip applauseSound = null;

    private AudioClip missileSound = null;

    private AudioClip shotExplosionSound = null;

    private AudioClip missileExplosionSound = null;

    private AudioClip baseExplosionSound = null;

  • 8/12/2019 Missile Commando

    22/47

    private AudioClip music = null;

    /* State variables. */

    private boolean playing = false;

    private boolean clearScreen = false;

    private boolean loadingSounds = false;

    /* Current game parameters. */

    private int score = 0;

    private int level = 0;

    private int speed = 0;

    private int delay = 0;

    private int missileCount = 0;

    private int shotCount = 0;

    /* Synchronization semaphores. */

    private Semaphore missileSemaphore;

    private Semaphore messageSemaphore;

    /* Fonts */

    private Font font;

    private FontMetrics fontMetrics;

    /* Strings */

  • 8/12/2019 Missile Commando

    23/47

  • 8/12/2019 Missile Commando

    24/47

    public synchronized void newGame ()

    {

    playing = true;

    clearScreen = true;

    stopThreads ();

    thread = new Thread (this);

    thread.start ();

    }

    /* The game engine. */

    public void run ()

    {

    int n;

    int newBases = 0;

    Thread.currentThread().setPriority (Thread.MIN_PRIORITY);

    score = 0;

    shotCount = 0;

    shots = 0;

  • 8/12/2019 Missile Commando

    25/47

    things = new Vector (32);

    missileSemaphore = new Semaphore ();

    messageSemaphore = new Semaphore ();

    getSounds ();

    createBases ();

    if (music != null)

    {

    music.loop ();

    }

    for (level = 1; ; level++)

    {

    if (level == 1)

    {

    if (startSound != null)

    {

    startSound.play ();

    }

    }

    else

    {

    if (applauseSound != null)

  • 8/12/2019 Missile Commando

    26/47

    {

    applauseSound.play ();

    }

    }

    messageSemaphore.take ();

    createMessage ("Level " + level);

    messageSemaphore.take ();

    messageSemaphore.give ();

    /* Missile speed. */

    speed = 5 + (level - 1);

    if (speed > (WORLD_HEIGHT / 10))

    {

    speed = WORLD_HEIGHT / 10;

    }

    /* Delay between missiles. */

    delay = 2000 - ((level-1)*200);

    if (delay < 500)

    {

    delay = 500;

    }

    /* Number of missiles. */

  • 8/12/2019 Missile Commando

    27/47

    missileCount = 5 + ((level-1)*5);

    /* Number of shots. */

    shotCount = missileCount * 2;

    /* Wait until missiles are ready. */

    missileSemaphore.take ();

    while (missileCount > 0)

    {

    try

    {

    Thread.sleep (delay);

    }

    catch (InterruptedException e)

    {

    }

    /* Fire a missile. */

    createMissile (speed);

    missileCount--;

    }

    /* Wait until missiles are dead. */

  • 8/12/2019 Missile Commando

    28/47

    missileSemaphore.take ();

    missileSemaphore.give ();

    /* See if any new bases can be created. */

    n = score - newBases*POINTS_NEW_BASE;

    while (countBases () < BASES && n >= POINTS_NEW_BASE)

    {

    createBase ();

    n -= POINTS_NEW_BASE;

    newBases++;

    }

    /* Game over? */

    n = countBases ();

    if (n == 0)

    {

    break;

    }

    else

    {

    score += n * POINTS_BASE;

    }

    }

  • 8/12/2019 Missile Commando

    29/47

    playing = false;

    if (music != null)

    {

    music.stop ();

    }

    /* Destroy the world! */

    for (int i = 0; i < 5; i++)

    {

    int x = (int) (Math.random () * WORLD_WIDTH);

    int y = (int) (Math.random () * WORLD_HEIGHT);

    things.addElement (new Explosion (this, Color.red, x, y, 500));

    }

    messageSemaphore.take ();

    createMessage ("GAME OVER");

    messageSemaphore.take ();

    messageSemaphore.give ();

    }

    /* Stop all running threads. */

    public void stopThreads ()

  • 8/12/2019 Missile Commando

    30/47

    {

    if (things != null)

    {

    Enumeration e;

    e = things.elements ();

    while (e.hasMoreElements ())

    {

    Thing thing = (Thing) e.nextElement ();

    thing.explode ();

    }

    }

    }

    /* Stop this applet. */

    public void stop ()

    {

    if (music != null)

    {

    music.stop ();

    }

    stopThreads ();

  • 8/12/2019 Missile Commando

    31/47

    if (thread != null)

    {

    thread.stop ();

    thread = null;

    }

    }

    /* Get all the sounds. */

    void getSounds ()

    {

    loadingSounds = true;

    repaint ();

    startSound = getAudioClip (getCodeBase (), "sounds/sub_dive_horn.au");

    applauseSound = getAudioClip (getCodeBase (), "sounds/applause.au");

    missileSound = getAudioClip (getCodeBase (), "sounds/missile.au");

    shotExplosionSound = getAudioClip (getCodeBase (), "sounds/shot.au");

    missileExplosionSound = getAudioClip (getCodeBase (), "sounds/beep_multi.au");

    baseExplosionSound = getAudioClip (getCodeBase (), "sounds/bzzzt.au");

    /* background music is disabled since the sound file is too

    large. */

    music = null; /* getAudioClip (getCodeBase (), "sounds/pink_panther.au"); */

    loadingSounds = false;

  • 8/12/2019 Missile Commando

    32/47

    }

    /* Create the bases. */

    void createBases ()

    {

    for (int i = 0; i < BASES; i++)

    {

    createBase ();

    }

    }

    /* Create one base, if possible. */

    void createBase ()

    {

    Enumeration e;

    boolean found;

    int i, x;

    for (i = 0, x = BASE_SPACING; i < BASES; i++, x += BASE_WIDTH + BASE_SPACING)

    {

    found = false;

    e = things.elements ();

  • 8/12/2019 Missile Commando

    33/47

    while (e.hasMoreElements ())

    {

    Thing thing = (Thing) e.nextElement ();

    if (thing instanceof Base && thing.X == x)

    {

    found = true;

    }

    }

    if (!found)

    {

    things.addElement (new Base (this, Color.blue, x,

    WORLD_HEIGHT - BASE_HEIGHT - 1,

    BASE_WIDTH,

    BASE_HEIGHT));

    break;

    }

    }

    }

    /* Create a shot explosion at x,y. */

    void createShotExplosion (int x, int y)

    {

  • 8/12/2019 Missile Commando

    34/47

    if (shots > MAX_SHOTS)

    {

    return;

    }

    things.addElement (new ShotExplosion (this, x, y));

    if (shotExplosionSound != null)

    {

    shotExplosionSound.play ();

    }

    shots++;

    }

    /* Create a base explosion at x,y. */

    void createBaseExplosion (int x, int y)

    {

    things.addElement (new BaseExplosion (this, x, y));

    if (baseExplosionSound != null)

    {

    baseExplosionSound.play ();

    }

    }

  • 8/12/2019 Missile Commando

    35/47

    /* Create a missile starting at x,y with speed. */

    void createMissile (int x1, int y1, int speed)

    {

    int x2, y2;

    Color color = Color.red;

    x2 = (int)(Math.random () * WORLD_WIDTH);

    if (x2 == 0) x2 = 1;

    y2 = WORLD_HEIGHT - 2;

    things.addElement (new Missile (this, color, x1, y1, x2, y2, speed));

    if (missileSound != null)

    {

    missileSound.play ();

    }

    }

    /* Create a missile at a random location with speed. */

    void createMissile (int speed)

    {

    int x1, y1;

  • 8/12/2019 Missile Commando

    36/47

    x1 = (int)(Math.random () * WORLD_WIDTH);

    if (x1 == 0) x1 = 1;

    y1 = 2;

    createMissile (x1, y1, speed);

    }

    /* Create a blinking message. */

    void createMessage (String string)

    {

    int w = fontMetrics.stringWidth (string);

    int x = WORLD_WIDTH/2 - w/2;

    int y = WORLD_HEIGHT/2;

    things.addElement (new Message (this, string, x, y));

    }

    /* Handle events. */

    public boolean handleEvent (Event e)

    {

    if (e.id == Event.MOUSE_DOWN) /* mouse click */

  • 8/12/2019 Missile Commando

    37/47

    {

    if (playing

    && shotCount > 0

    && e.x >= 0 && e.x = 0 && e.y

  • 8/12/2019 Missile Commando

    38/47

    {

    Enumeration e;

    int nbases = 0, nexplosions = 0;

    e = things.elements ();

    while (e.hasMoreElements ())

    {

    Thing thing = (Thing) e.nextElement ();

    if (thing != missile && thing.isAlive ())

    {

    if (thing.hit (missile))

    {

    thing.explode ();

    if (thing instanceof Base)

    {

    nbases++;

    }

    else if (thing instanceof ShotExplosion)

    {

    nexplosions++;

    score += POINTS_MISSILE;

    if (missileExplosionSound != null)

    {

  • 8/12/2019 Missile Commando

    39/47

    missileExplosionSound.play ();

    }

    }

    }

    }

    }

    if (nbases > 0)

    {

    createBaseExplosion (missile.X, missile.Y);

    }

    if (nbases > 0 || nexplosions > 0)

    {

    missile.explode ();

    }

    }

    /* Update (paint, erase) things. */

    public synchronized void updateThings (Graphics g)

    {

    int i, j;

    Enumeration e;

  • 8/12/2019 Missile Commando

    40/47

    e = things.elements ();

    while (e.hasMoreElements ())

    {

    Thing thing = (Thing) e.nextElement ();

    if (thing.isAlive ())

    {

    thing.paint (g);

    if (thing instanceof Missile)

    {

    checkCollision ((Missile) thing);

    }

    }

    else

    {

    thing.erase (g);

    things.removeElement (thing);

    if (thing instanceof Message)

    {

    messageSemaphore.give ();

    }

    else if (thing instanceof ShotExplosion)

  • 8/12/2019 Missile Commando

    41/47

    {

    shots--;

    }

    }

    }

    }

    /* Return the number of remaining missiles. */

    public int countMissiles ()

    {

    Enumeration e;

    int count = 0;

    e = things.elements ();

    while (e.hasMoreElements ())

    {

    Thing thing = (Thing) e.nextElement ();

    if (thing instanceof Missile && thing.isAlive ())

    {

    count++;

    }

    }

  • 8/12/2019 Missile Commando

    42/47

    return count;

    }

    /* Return the number of remaining bases. */

    public int countBases ()

    {

    Enumeration e;

    int count = 0;

    e = things.elements ();

    while (e.hasMoreElements ())

    {

    Thing thing = (Thing) e.nextElement ();

    if (thing instanceof Base && thing.isAlive ())

    {

    count++;

    }

    }

    return count;

    }

  • 8/12/2019 Missile Commando

    43/47

    /* Draw the borders. */

    public void updateBorder (Graphics g)

    {

    g.setColor (Color.black);

    g.drawRect (0, 0, WORLD_WIDTH + SCORE_WIDTH - 1, WORLD_HEIGHT - 1);

    g.drawLine (WORLD_WIDTH, 0, WORLD_WIDTH, WORLD_HEIGHT);

    }

    String numberToZeroPaddedString (int number, int length)

    {

    StringBuffer s;

    s = new StringBuffer (Integer.toString (number));

    while (s.length () < length)

    {

    s.insert (0, "0");

    }

    return s.toString ();

    }

    /* Draw the score. */

  • 8/12/2019 Missile Commando

    44/47

    public synchronized void updateScore (Graphics g)

    {

    int h, w;

    int x, y;

    int n;

    StringBuffer s;

    w = fontMetrics.stringWidth ("00000");

    h = fontMetrics.getHeight ();

    x = WORLD_WIDTH + 5;

    g.setColor (Color.black);

    y = h;

    g.drawString (scoreString, x, y);

    y += h;

    g.clearRect (x, y - h, w, h);

    g.drawString (numberToZeroPaddedString (score, 5), x, y);

    y += 2*h;

    g.drawString (shotString, x, y);

    y += h;

    g.clearRect (x, y - h, w, h);

  • 8/12/2019 Missile Commando

    45/47

    g.drawString (numberToZeroPaddedString (shotCount, 5), x, y);

    }

    /* Don't clear the screen; call paint. */

    public void update (Graphics g)

    {

    paint (g);

    }

    /* Paint the screen. */

    public void paint (Graphics g)

    {

    if (clearScreen)

    {

    g.setColor (Color.lightGray);

    g.fillRect (0, 0, WORLD_WIDTH + SCORE_WIDTH, WORLD_HEIGHT);

    clearScreen = false;

    }

    if (loadingSounds)

    {

    int w = fontMetrics.stringWidth (loadingString);

  • 8/12/2019 Missile Commando

    46/47

    int x = WORLD_WIDTH/2 - w/2;

    int y = WORLD_HEIGHT/2;

    g.setColor (Color.black);

    g.drawString (loadingString, x, y);

    clearScreen = true;

    }

    else if (!playing && (things == null || things.size () == 0))

    {

    int w = fontMetrics.stringWidth (welcomeString);

    int x = WORLD_WIDTH/2 - w/2;

    int y = WORLD_HEIGHT/2;

    g.setColor (Color.black);

    g.drawString (welcomeString, x, y);

    }

    else if (things != null)

    {

    Graphics gc = g.create (0, 0, WORLD_WIDTH, WORLD_HEIGHT);

    updateThings (gc);

    /* No more missiles. */

    if (missileSemaphore != null && countMissiles () == 0 && missileCount == 0)

    {

    missileSemaphore.give ();

    }

  • 8/12/2019 Missile Commando

    47/47

    }

    updateBorder (g);

    updateScore (g);

    }

    }

    /*

    Local variables:

    eval: (progn (make-local-variable 'compile-command) (setq compile-command (concat "javac " buffer-

    file-name)))

    End:

    */