
/* 
   The sub killer applet is based on KeyboardAnimationApplet, which is
   a framework for applets that display animated action while allowing
   keyboard input from the user to affect the action.  See the file
   KeyboardAnimationApplet.java for more information.
   
   This "starter file" for the sub killer game was written
   by David Eck, October 2, 1998.
*/


import java.awt.*;        // for access to GUI classes
import java.awt.event.*;  // for access to the KeyEvent class


public class SubKiller extends KeyboardAnimationApplet {


   protected void doInitialization(int width, int height) {
         // This routine will be called once, when the applet
         // is first created.  Do any necessarily of the applet
         // and its instance variables here.  The parameters
         // width and height give the size of the drawing area.
         
      setBackground(Color.gray);  // This color will be used for a border
                                  // around the applet when the applet does
                                  // NOT have the keyboard focus.
                                  
      initSubmarine(width, height);  // Initialize the things that appear in the applet.
      initBoat(width, height);       //    (These routines are defined below.)
      
   } // end init()


   synchronized public void drawFrame(Graphics g, int width, int height) {
          // This routine will be called each time a frame needs to be
          // drawn.  The parameters width and height specify the size of
          // the drawing area.  The graphics context g can be used for
          // drawing the frame.
   
       // First, fill the whole drawing area with green
       
       g.setColor(Color.green);
       g.fillRect(0,0,width,height);
       
       // Draw a message in the upper left corner showing the number
       // of seconds that the animation has been running.  The method
       // getElapsedTime() is defined in the KeyboardAnimationClass.
       // It returns the elapsed time in milliseconds.
       
       long seconds = getElapsedTime() / 1000;
       g.setColor(Color.black);
       g.drawString("Elapsed time: " + seconds + " seconds", 10,  20);
       
       // Now, draw the objects in the scene. These subroutines
       // are defined below.  They also change values of instance
       // variables so that the scene will change from one frame to
       // the next.
       
       doBoatFrame(g, width, height);
       doSubmarineFrame(g, width, height);
       
   } // end drawFrame()
   
   
   synchronized public void keyPressed(KeyEvent evt) {
          // This routine will be called each time the user presses
          // a key on the keyboard (while the applet has the keyboard
          // focus).  The value of evt.getKeyCode() tells which
          // key was pressed.  For this applet, only the
          // arrow keys will have any effect.  The codes for the
          // arrow keys are KeyEvent.VK_UP, KeyEvent.VK_DOWN,
          // KeyEvent.VK_LEFT, and KeyEvent.VK_RIGHT.

      int code = evt.getKeyCode();  // which key was pressed

      if (code == KeyEvent.VK_UP) {  // Make the submarine start exploding.
         if (!subIsExploding)        // (This is for the starter applet only!)
            subIsExploding = true;   // You should take this out!!!)
      }
   
   } // end keyPressed()
   

   // -------------- Instance variables and method for the boat -------------
   
   int boatCenterX;  // horizontal coordinate of the center of the boat
   int boatCenterY;  // vertical coordinate of the center of the boat

   void initBoat(int width, int height) {
          // Initialize instance variables that pertain to the boat.
      boatCenterX = width/2;
      boatCenterY = 80;
   }

   void doBoatFrame(Graphics g, int width, int height) {
          // Draw the boat.  First, if the center of the boat has moved off the
          // drawing area, move it back to the edge of the drawing area.
      if (boatCenterX < 0)
         boatCenterX = 0;
      else if (boatCenterX > width)
         boatCenterX = width;
      g.setColor(Color.blue);
      g.fillRoundRect(boatCenterX - 40, boatCenterY - 20, 80, 40, 20, 20);
   }


   // -------------- Instance variables and method for the submarine -------------
   
   int subCenterX;  // horizontal coordinate of the center of the submarine
   int subCenterY;  // vertical coordinate of the center of the submarine
   
   boolean subIsMovingLeft;  // sub can be moving left or right; this variable tells which
   boolean subIsExploding;   // the sub can explode; this is true if the sub is exploding
   int explosionFrameNumber; // while the sub is exploding, this tells for how many
                             //              frames the explosiong has been in progress
  
   void initSubmarine(int width, int height) {
          // Initialize the instance variables that pertain to the submarine.
          // The sub is placed in a random horizontal position, 40 pixels from
          // the bottom of the drawing area.  Its direction of motion is
          // set randomly to either left or right.  At the beginning, the
          // sub is not exploding.
      subCenterX = (int)(width * Math.random());
      subCenterY = height - 40;
      subIsExploding = false;
      explosionFrameNumber = 0;
      if (Math.random() < 0.5)
         subIsMovingLeft = true;
      else
         subIsMovingLeft = false;
   }
   
   void doSubmarineFrame(Graphics g, int width, int height) {
         // Draw the submarine and update the instance variables that
         // describe it.  The sub has two very different states,
         // depending on whether or not it is exploding.

      if (subIsExploding) {
      
         if (explosionFrameNumber == 0)      // Explosion is just starting.
            play(getCodeBase(), "swish.au"); // Start playing the shish sound

         explosionFrameNumber++;  // go to next frame of explosion sequence
            
         if (explosionFrameNumber == 14)  // In the 14-th frame...
            initSubmarine(width,height);  //    ... create a new sub
            
         else if (explosionFrameNumber > 10) { // For frames 11, 12, and 13,
                                               //   there is no sub
         }
         
         else {  // For frames 1 through 10, draw the sub under an expanding explosion
            g.setColor(Color.black);
            g.fillOval(subCenterX - 30, subCenterY - 15, 60, 30);
            g.setColor(Color.yellow);
            g.fillOval(subCenterX - 4*explosionFrameNumber,
                       subCenterY - 2*explosionFrameNumber,
                       8*explosionFrameNumber,
                       4*explosionFrameNumber);
            g.setColor(Color.red);
            g.fillOval(subCenterX - 2*explosionFrameNumber,
                       subCenterY - explosionFrameNumber/2,
                       4*explosionFrameNumber,
                       explosionFrameNumber);
         }
      }
      
      // Note that subIsExploding might have changed from true to false
      // in the above if statement (if initSubmarine() is called).
      
      if (!subIsExploding) { // move the sub and draw it in its new position
      
         if (Math.random() < 0.04)               // One time out of 25, on average...
            subIsMovingLeft = !subIsMovingLeft;  //   ...randomly reverse direction
            
         if (subIsMovingLeft) { 
            subCenterX -= 5;        // Move the sub left 5 pixels.
            if (subCenterX <= 0) {  // If sub has moved off left hand edge of applet...
               subCenterX = 0;      //       ...move it back to the left edge...
               subIsMovingLeft = false; //  ...and start it moving right.
            }
         }
         else {
            subCenterX += 5;           // Move the sub right 5 pixels.
            if (subCenterX > width) {  // If the sub has moved off the right edge...
               subCenterX = width;     //    ...move it back to the right edge...
               subIsMovingLeft = true; //    ...and start it moving left.
            }
         }
         g.setColor(Color.black);  // Draw the sub
         g.fillOval(subCenterX - 30, subCenterY - 15, 60, 30);
      }

   }  // end doSubmarineFrame 
   
   //----------------------------------------------------------------------------

} // end class SubKiller
