home *** CD-ROM | disk | FTP | other *** search
/ Java 1.2 How-To / JavaHowTo.iso / code / ch09.txt < prev    next >
Text File  |  1998-12-14  |  26KB  |  1,212 lines

  1. Dialer.java:
  2.  
  3. import java.awt.*;
  4. import java.awt.event.*;
  5. import java.applet.*;
  6.  
  7. /*
  8.  * the dialer applet
  9.  */
  10. public class Dialer extends Applet implements ActionListener {
  11.  
  12.  
  13. AudioClip touchTones[] = new AudioClip[12];
  14.  
  15. public Button NumberButton1;
  16. public Button NumberButton2;
  17. public Button NumberButton3;
  18. public Button NumberButton4;
  19. public Button NumberButton5;
  20. public Button NumberButton6;
  21. public Button NumberButton7;
  22. public Button NumberButton8;
  23. public Button NumberButton9;
  24. public Button NumberButton0;
  25. public Button PoundButton;
  26. public Button StarButton; 
  27. /*
  28.  * called when the applet is loaded
  29.  * load audio clips and add the keypad panel
  30.  */
  31. public void init () {
  32.  
  33.     int i;
  34.     String name;
  35.  
  36.     for (i=0; i<10; i+=1) {
  37.         name = "touchtone."+i+".au";
  38.         showStatus ("Getting "+name);
  39.         touchTones[i] = getAudioClip (getCodeBase(), name);
  40.     }
  41.     name = "touchtone.star.au";
  42.     showStatus ("Getting "+name);
  43.     touchTones[10] = getAudioClip (getCodeBase(), name);
  44.  
  45.     name = "touchtone.pound.au";
  46.     showStatus ("Getting "+name);
  47.     touchTones[11] = getAudioClip (getCodeBase(), name);
  48.  
  49.     setLayout(new BorderLayout());
  50.  
  51.     //add ("Center", keypad = new Keypad (touchTones));
  52.  
  53.     //Font    font = new Font ("Times", Font.BOLD, 14);
  54.  
  55.     Color   miscColor = new Color (0, 0, 255);
  56.     //setFont (font);
  57.  
  58.     NumberButton1 =  new Button ("1");
  59.     add ("South",NumberButton1);
  60.     NumberButton2 = new Button ("2");
  61.     add ("South", NumberButton2 );
  62.     NumberButton3 = new Button ("3");
  63.     add ("South", NumberButton3 );
  64.     NumberButton4 = new Button ("4");
  65.     add ("South", NumberButton4);
  66.     NumberButton5 = new Button ("5");
  67.     add ("South", NumberButton5);
  68.     NumberButton6 = new Button ("6");
  69.     add ("South", NumberButton6 );
  70.  
  71.     NumberButton7 = new Button ("7");
  72.     add ("South", NumberButton7);
  73.     NumberButton8 = new Button ("8");
  74.     add ("South", NumberButton8 );
  75.     NumberButton9 = new Button ("9");
  76.     add ("South", NumberButton9 );
  77.  
  78.     PoundButton= new Button ("*");
  79.     add ("South", PoundButton );
  80.     PoundButton.setBackground (miscColor);
  81.  
  82.     NumberButton0 =  new Button ("0");
  83.     add ("South", NumberButton0);
  84.  
  85.     StarButton = new Button ("#");
  86.     add ("South", StarButton);
  87.     StarButton.setBackground (miscColor);
  88.  
  89.     setLayout (new GridLayout (4, 3, 4, 4));
  90.  
  91.     NumberButton1.addActionListener(this);
  92.     NumberButton2.addActionListener(this);
  93.     NumberButton3.addActionListener(this);
  94.     NumberButton4.addActionListener(this);
  95.     NumberButton5.addActionListener(this);
  96.     NumberButton6.addActionListener(this);
  97.     NumberButton7.addActionListener(this);
  98.     NumberButton8.addActionListener(this);
  99.     NumberButton9.addActionListener(this);
  100.     NumberButton0.addActionListener(this);
  101.     PoundButton.addActionListener(this);
  102.     StarButton.addActionListener(this);
  103. }
  104.  
  105. public void actionPerformed (ActionEvent ev)
  106. {
  107.     Object object1 = ev.getSource();
  108.     if (object1 == StarButton)
  109.         touchTones[10].play ();
  110.     else if (object1 == PoundButton)
  111.         touchTones[11].play ();
  112.     else if (object1 == NumberButton0)
  113.         touchTones[0].play ();
  114.     else if (object1 == NumberButton1)
  115.         touchTones[1].play ();
  116.     else if (object1 == NumberButton2)
  117.         touchTones[2].play ();
  118.     else if (object1 == NumberButton3)
  119.         touchTones[3].play ();
  120.     else if (object1 == NumberButton4)
  121.         touchTones[4].play ();
  122.     else if (object1 == NumberButton5)
  123.         touchTones[5].play ();
  124.     else if (object1 ==NumberButton6)
  125.         touchTones[6].play ();
  126.     else if (object1 == NumberButton7)
  127.         touchTones[7].play ();
  128.     else if (object1 ==NumberButton8)
  129.         touchTones[8].play ();
  130.     else if (object1 == NumberButton9)
  131.         touchTones[9].play ();
  132. }
  133. }
  134.  
  135.  
  136.  
  137.  
  138.  
  139.  
  140.  
  141.  
  142.  
  143. Bounce.java:
  144.  
  145. import java.awt.*;
  146. import java.awt.event.*;
  147. import java.applet.*;
  148. import java.awt.image.ImageObserver;
  149.  
  150. /*
  151.  * a class describing a single ball
  152.  */
  153. class Ball {
  154.  
  155. /*
  156.  * the image for this ball
  157.  */
  158. Image img;
  159.  
  160. /*
  161.  * x position and velocity
  162.  */
  163. double x, dx;    // x position and velocity
  164.  
  165. /*
  166.  * y position and velocity
  167.  */
  168. double y, dy;    // y position and velocity
  169.  
  170. /*
  171.  * initialize the position and velocity
  172.  * to random values
  173.  */
  174. void random () {
  175.     x = 10 + 380*Math.random ();
  176.     y = 10 + 200*Math.random ();
  177.     dx = 5 - 10*Math.random ();
  178.     dy = 5 - 10*Math.random ();
  179. }
  180.  
  181. /**
  182.  * calculate the next position of this ball
  183.  * and make sure it bounces off the edge of the panel
  184.  * @param d - dimension of the bounding panel
  185.  */
  186. void compute (Dimension d) {
  187.     if (x <= 0 || x > d.width) dx = -dx;    // bounce horizontal
  188.     if (y <= 0 || y > d.height) dy = -dy;    // bounce vertical
  189.     x += dx;
  190.     y += dy;
  191. }
  192.  
  193. /**
  194.  * draw the ball image
  195.  * @param g - destination graphics object
  196.  * @param obs - parent image observer
  197.  */
  198. public void paint (Graphics g, ImageObserver obs) {
  199.  
  200.     g.drawImage (img, (int) x-10, (int) y-10, obs);
  201. }
  202. }
  203.  
  204. /*
  205.  * the panel containing the bouncing balls
  206.  */
  207. class BouncePanel extends Panel implements Runnable {
  208.  
  209. /*
  210.  * the number of balls
  211.  */
  212. final int nballs = 4;
  213.  
  214. /*
  215.  * the array holding all the balls
  216.  */
  217. Ball balls[] = new Ball[10];
  218.  
  219. /*
  220.  * offscreen image
  221.  */
  222. Image offimg;
  223.  
  224. /*
  225.  * size of offscreen image
  226.  */
  227. Dimension offsize; 
  228.  
  229. /*
  230.  * graphics object associated with offscreen image
  231.  */
  232. Graphics offg;
  233.  
  234. /*
  235.  * thread for periodic updating
  236.  */
  237. Thread thread;
  238.  
  239. /*
  240.  * The thread recalculates each ball position and
  241.  * redraws them
  242.  */
  243. public void run() {
  244.  
  245.     offsize = getSize();
  246.     offimg = createImage (offsize.width, offsize.height);
  247.     offg = offimg.getGraphics();
  248.     while (true) {
  249.         for (int i=0; i<nballs; i+=1) {
  250.             balls[i].compute (offsize); 
  251.         }
  252.         repaint ();
  253.         try {
  254.             Thread.sleep (25);
  255.         } catch (InterruptedException e) {
  256.             break;
  257.         }
  258.     }
  259. }
  260.  
  261. /**
  262.  * Override update to avoid erase flicker
  263.  * @param g - destination graphics object
  264.  */
  265. public synchronized void update (Graphics g) {
  266.  
  267.     offg.setColor (Color.lightGray);
  268.     offg.fillRect (0, 0, offsize.width, offsize.height);
  269.  
  270.     for (int i = 0 ; i < nballs ; i++)
  271.         balls[i].paint (offg, this);
  272.     offg.setColor (Color.black);
  273.     offg.drawRect (0, 0, offsize.width-1, offsize.height-1);
  274.     g.drawImage(offimg, 0, 0, this);
  275. }
  276.  
  277. /*
  278.  * Start the update thread
  279.  */
  280. public void start() {
  281.  
  282.     thread = new Thread(this);
  283.     thread.start();
  284. }
  285.  
  286. /*
  287.  * Stop the update thread
  288.  */
  289. public void stop()
  290. {
  291.  
  292.    if (thread != null)
  293.      thread = null;
  294. }
  295.  
  296. }
  297.  
  298. /*
  299.  * the applet proper
  300.  */
  301. public class Bounce extends Applet implements ActionListener
  302. {
  303.  
  304. /*
  305.  * instance of BouncePanel
  306.  */
  307. BouncePanel panel;
  308.  
  309. /*
  310.  * an array containing the images for the balls
  311.  */
  312. Image img[] = new Image[4];
  313.  
  314. /*
  315.  * the audio clip to be played in a loop
  316.  */
  317. AudioClip sound;
  318. Button btnStart;
  319. Button btnStop;
  320. /*
  321.  * Called when the applet is loaded
  322.  * Create an instance of bounce panel and add the start button
  323.  * and load images
  324.  */
  325. public void init() {
  326.  
  327.     setLayout(new BorderLayout());
  328.  
  329.     panel = new BouncePanel ();
  330.     add ("Center", panel);
  331.     Panel p = new Panel ();
  332.     add ("South", p);
  333.     btnStart = new Button("Start");
  334.     p.add (btnStart);
  335.     btnStop = new Button("Stop");
  336.     p.add (btnStop);
  337.     btnStart.addActionListener(this);
  338.     btnStop.addActionListener(this);
  339.  
  340.     sound = getAudioClip(getCodeBase(),  "sound.au");
  341.  
  342.     img[0] = getImage (getDocumentBase(), "whiteball.gif");
  343.     img[1] = getImage (getDocumentBase(), "redball.gif");
  344.     img[2] = getImage (getDocumentBase(), "blueball.gif");
  345.     img[3] = getImage (getDocumentBase(), "greenball.gif");
  346.     for (int i=0; i<panel.nballs; i+=1) {
  347.         panel.balls[i] = new Ball ();
  348.         panel.balls[i].img = img[i & 3];
  349.     }
  350. }
  351.  
  352. /*
  353.  * Called when the applet is started
  354.  * Don't do anything
  355.  */
  356. public void start () {
  357.  
  358. }
  359.  
  360. /*
  361.  * Called when the applet is stopped
  362.  */
  363. public void stop() {
  364.  
  365.     panel.stop();
  366.     sound.stop ();
  367. }
  368.  
  369. /*
  370.  * Handle start button press by randomizing balls
  371.  */
  372. public void actionPerformed(ActionEvent ev)
  373. {
  374.     Object object1 = ev.getSource();
  375.     if (object1 == btnStart)
  376.     {
  377.         for (int i=0; i<panel.nballs; i+=1)
  378.             panel.balls[i].random ();
  379.         panel.start ();
  380.         sound.loop ();
  381.     }
  382.     if (object1 == btnStop)
  383.     {
  384.         sound.stop ();
  385.     }
  386. }
  387.  
  388. }
  389.  
  390.  
  391.  
  392.  
  393.  
  394.  
  395.  
  396. Guitar.java:
  397.  
  398. import java.awt.*;
  399. import java.awt.event.*;
  400. import java.applet.*;
  401.  
  402. /*
  403.  * the applet class
  404.  */
  405. public class Guitar extends Applet implements ActionListener {
  406.  
  407. /*
  408.  * the guitar chords
  409.  */
  410. AudioClip chords[] = new AudioClip[7];
  411.  
  412. /*
  413.  * the drum clip
  414.  */
  415. AudioClip drum;
  416. String chordnames[] = {"a", "c", "d", "low_e", "high_e", "g", "chaa"};
  417. String drumbeat  = "drum";
  418. Button chordbuttons[] = new Button[7];
  419. Button btnStart;
  420. Button btnStop;
  421. /*
  422.  * Called when the applet is loaded
  423.  * Load all sounds and add user interface
  424.  */
  425. public void init () {
  426.  
  427.     String name;
  428.     int i;
  429.     Panel keyboard = new Panel();
  430.     Panel controls = new Panel();
  431.  
  432.     this.setLayout(new BorderLayout());
  433.     keyboard.setLayout(new FlowLayout());
  434.     controls.setLayout(new FlowLayout());
  435.     add ("Center", keyboard);
  436.     add ("South", controls);
  437.  
  438.     for (i=0; i<7; i+=1) {
  439.         name = chordnames[i]+".au";
  440.         showStatus ("Getting " + name);
  441.         chords[i] = getAudioClip (getCodeBase(), name);
  442.         chordbuttons[i] = new Button (chordnames[i]);
  443.            keyboard.add (chordbuttons[i]);
  444.         chordbuttons[i].addActionListener(this);
  445.     }
  446.     showStatus ("Getting " + drumbeat + ".au");
  447.     drum = getAudioClip (getCodeBase(), drumbeat + ".au");
  448.     btnStart = new Button ("Start");
  449.     controls.add (btnStart);
  450.     btnStop = new Button ("Stop");
  451.     controls.add (btnStop);
  452.     btnStop.addActionListener(this);
  453.     btnStart.addActionListener(this); 
  454. }
  455.  
  456. /*
  457.  * Handle button presses
  458.  * @param ev - event object
  459.  * @param arg - target object
  460.  */
  461. public void actionPerformed (ActionEvent ev)
  462. {
  463.     Object object1 = ev.getSource();
  464.     if (object1 == chordbuttons[0])
  465.     {
  466.         chords[0].play ();
  467.     }
  468.     else if (object1 == chordbuttons[1])
  469.     {
  470.         chords[1].play ();
  471.     }
  472.     else if (object1 == chordbuttons[2])
  473.     {
  474.         chords[2].play ();
  475.     }
  476.     else if (object1 == chordbuttons[3])
  477.     {
  478.         chords[3].play ();
  479.     }
  480.     else if (object1 == chordbuttons[4])
  481.     {
  482.         chords[4].play ();
  483.     }
  484.     else if (object1 == chordbuttons[5])
  485.     {
  486.         chords[5].play ();
  487.     }
  488.     else if (object1 == chordbuttons[6])
  489.     {
  490.         chords[6].play ();
  491.     }
  492.         else if (object1 == btnStart) {
  493.             drum.loop ();
  494.     }
  495.     else if (object1 == btnStop)
  496.      {
  497.             drum.stop ();
  498.      }
  499. }
  500. }
  501.  
  502.  
  503.  
  504.  
  505.  
  506.  
  507.  
  508. InvaderApp.java:
  509.  
  510. import java.awt.*;
  511. import java.awt.event.*;
  512. import java.applet.Applet;
  513. import java.awt.image.*;
  514.  
  515. /**
  516.  * A class that describes a target "invader"
  517.  * This hold a single invader
  518.  */
  519. class Invader {
  520.  
  521. /*
  522.  * this invader's position and velocity
  523.  */
  524. double x, y, dx, dy;
  525.  
  526. /*
  527.  * this invader's missile position and velocity
  528.  * only one missile allowed per invader
  529.  */
  530. int mx, my, mdy; 
  531.  
  532. /*
  533.  * The images for an invader
  534.  */
  535. Image img[] = new Image[4];
  536.  
  537. /*
  538.  * inplay is true if this invader has not been killed
  539.  */
  540. boolean inplay;
  541.  
  542. /*
  543.  * fired is set to true when this invader fires a missile
  544.  */
  545. boolean fired = false;
  546.  
  547. /*
  548.  * state is used to cycle through the four images
  549.  * of this invader
  550.  */
  551. double state;
  552.  
  553. /*
  554.  * value is the score value; it depends on the speed
  555.  */
  556. int value;
  557.  
  558. /*
  559.  * Initialize position and speed for this invader
  560.  */
  561. void random (int speed, int w, int h) {
  562.  
  563.     x = 10 + (w-20)*Math.random ();
  564.     y = 10 + ((h>>1)-20)*Math.random ();
  565.     dx = (speed>>1) - speed*Math.random ();
  566.     dy = (speed>>1) - speed*Math.random ();
  567.     inplay = true;
  568.     state = 3 * Math.random ();
  569.     fired = false;
  570.     mdy = 20;
  571.     value = speed * 10; 
  572. }
  573.  
  574. /*
  575.  * Calculate new invader and missile position
  576.  * Also fires a missile at random
  577.  * @param w    panel width
  578.  * @param h    panel height
  579.  */
  580. void compute (int w, int h) {
  581.  
  582.     if (x <= 0 || x > w) dx = -dx;
  583.     if (y <= 0 || y > h>>1) dy = -dy;
  584.     if (my > h-20) fired = false;
  585.     if (fired) my += mdy;
  586.     else my = 0;
  587.     if (inplay && !fired && Math.random () > 0.99) {
  588.         fired = true;
  589.         mx = (int) x; my = (int) y+25;
  590.     }
  591.     x += dx; y += dy;
  592. }
  593.  
  594. /*
  595.  * paint invader and missile (if it has been fired)
  596.  * @param g - destination graphics object
  597.  * @param obs - imageobserver associated 
  598.  * with this graphics context
  599. */
  600. public void paint (Graphics g, ImageObserver obs) {
  601.  
  602.     int whichImage; 
  603.  
  604.     if (inplay) {
  605.         whichImage = (int) state;
  606.         g.drawImage (img[whichImage & 0x3], (int) x-25,
  607.             (int) y-25, obs);
  608.         state += .25;
  609.     }
  610.     if (fired) {
  611.         g.setColor (Color.green);
  612.         g.drawLine ((int) mx, (int) my, (int) mx, (int) my-10);
  613.     }
  614. }
  615.  
  616. /*
  617.  * Tests whether the player's missile has hit this invader
  618.  * Returns true if invader is hit
  619.  * @param pmx - player's missile x position
  620.  * @param pmy - player's missile y position
  621.  */
  622. boolean killer (int pmx, int pmy) {
  623.  
  624.     int deltaX, deltaY;
  625.  
  626.     if (!inplay) return false;
  627.         deltaX = (int) Math.abs (x-pmx);
  628.         deltaY = (int) Math.abs (y-pmy);
  629.         if (deltaX < 20 && deltaY < 20) {
  630.             inplay = false;
  631.             return true;
  632.         }
  633.         return false;
  634. }
  635. }
  636.  
  637. /**
  638.  * A class to describe the player, very similar to Invader
  639.  * except in reverse
  640.  */
  641. class Player {
  642.  
  643. /*
  644.  * position of the player
  645.  */
  646. int x, y=-100;
  647.  
  648. /*
  649.  * position of the player's missile
  650.  */
  651. int mx, my, mdy = -20;
  652.  
  653. /*
  654.  * two different player images
  655.  */
  656. Image img1, img2;
  657.  
  658. /*
  659.  * fired is true if player has fired a missile
  660.  * inplay is true if the game is not over
  661.  */
  662. boolean fired = false, inplay=true;
  663.  
  664. /*
  665.  * called when a player fires a missile
  666.  */
  667. void fire () {
  668.  
  669.     if (fired || !inplay) return;
  670.     mx = x; my = y;
  671.     fired = true;
  672. }
  673.  
  674. /*
  675.  * Calculate next missile position
  676.  */
  677. void compute () {
  678.  
  679.     if (my < 0) fired = false;
  680.     if (fired) my += mdy;
  681.     else my = y;
  682. }
  683.  
  684. /**
  685.  * Paint player and missile
  686.  * @param g - destination graphics object
  687.  * @param obs - image observer
  688.  */
  689. public void paint (Graphics g, ImageObserver obs) {
  690.  
  691.     if (fired) {
  692.         if (inplay) g.drawImage (img2, x-25, y, obs);
  693.         g.setColor (Color.white);
  694.         g.drawLine (mx, my, mx, my+10);
  695.     } else if (inplay) g.drawImage (img1, x-25, y, obs);
  696. }
  697.  
  698. /**
  699.  * Returns true if the player has been killed
  700.  * @param bmx, bmy - position of enemy missile
  701.  */
  702. boolean killer (int bmx, int bmy) {
  703.  
  704.     int dx, dy;
  705.  
  706.     if (!inplay) return false;
  707.     dx = (int) Math.abs (x-bmx);
  708.     dy = (int) Math.abs (y-bmy);
  709.     if (dx < 20 && dy < 20) {
  710.         return true;
  711.     }
  712.     return false;
  713. }
  714. }
  715.  
  716. /*
  717.  * much of the game logic is here
  718.  */
  719. class Playfield extends Panel implements Runnable, MouseListener, MouseMotionListener
  720. {
  721.  
  722. static final int PLAYER_HIT = 1;
  723. static final int INVADER_HIT = 2;
  724.  
  725. InvaderApp invaderApp;
  726.  
  727. /*
  728.  * the number of invaders in play
  729.  */
  730. int NInvaders=0;
  731.  
  732. /*
  733.  * the maximum number of invaders possible
  734.  */
  735. final int MaxInvaders = 32;
  736.  
  737. /*
  738.  * array of invaders
  739.  */
  740. Invader invaders[] = new Invader[MaxInvaders];
  741. Player player;
  742.  
  743. /*
  744.  * offscreen image for double-buffering
  745.  */
  746. Image offscreen;
  747.  
  748. /*
  749.  * dimension of offscreen graphics image
  750.  */
  751. Dimension psize;
  752.  
  753. /*
  754.  * graphics object associated with offscreen image
  755.  */
  756. Graphics offgraphics;
  757.  
  758. /*
  759.  * game action thread
  760.  */
  761. Thread theThread;
  762.  
  763. /*
  764.  * the playfield background color
  765.  */
  766. Color bgcolor = new Color (51, 0, 153);
  767. int score, playerLives, playLevel;
  768. Font font;
  769.  
  770. /**
  771.  * constructor saves instance of the applet
  772.  * @param invaderApp - instance of the applet
  773.  */
  774. public Playfield (InvaderApp invaderApp) {
  775.  
  776.     this.invaderApp = invaderApp;
  777.     addMouseListener(this);
  778.     addMouseMotionListener(this); 
  779.  
  780. }
  781.  
  782. /*
  783.  * game action thread
  784.  */
  785. public void run() {
  786.  
  787.     psize = getSize();
  788.     offscreen = createImage (psize.width, psize.height);
  789.     offgraphics = offscreen.getGraphics ();
  790.     font = new Font ("TimesRoman", Font.BOLD, 18);
  791.     offgraphics.setFont (font);
  792.  
  793.     while (true) {
  794.         compute ();
  795.         repaint ();
  796.         try {
  797.             Thread.sleep(25);
  798.         } catch (InterruptedException e) { }
  799.     }
  800. }
  801.  
  802. /*
  803.  * calculate new positions for all objects
  804.  */
  805. synchronized void compute () {
  806.  
  807.     for (int i=0; i<NInvaders; i+=1) {
  808.         invaders[i].compute (psize.width, psize.height);
  809.         if (invaders[i].killer (player.mx, player.my)) {
  810.             invaderApp.hit (INVADER_HIT);
  811.             player.fired = false;
  812.             score += invaders[i].value;
  813.         }
  814.         if (player.killer (invaders[i].mx, invaders[i].my)) {
  815.             invaderApp.hit (PLAYER_HIT);
  816.             invaders[i].fired = false;
  817.             playerLives -= 1;
  818.             if (playerLives < 1) player.inplay = false;
  819.         }
  820.     }
  821.     player.compute ();
  822. }
  823.  
  824. /**
  825.  * override default update
  826.  * draw into offscreen image and then copy it to the screen
  827.  * @param g - destination graphics object
  828.  */
  829. public synchronized void update(Graphics g) {
  830.  
  831.     offgraphics.setColor (bgcolor);
  832.     offgraphics.fillRect (0, 0, psize.width, psize.height);
  833.  
  834.     for (int i = 0 ; i < NInvaders ; i++)
  835.         if (invaders[i].inplay) invaders[i].paint (offgraphics, this);
  836. player.paint (offgraphics, this);
  837.  
  838.     offgraphics.setColor (Color.green);
  839.     offgraphics.drawString ("Score", 10, 20);
  840.     offgraphics.drawString (Integer.toString (score), 60, 20);
  841.     offgraphics.drawString ("Level", psize.width>>1, 20);
  842.     offgraphics.drawString (Integer.toString (playLevel),
  843.         (psize.width>>1)+50, 20);
  844.     offgraphics.drawString ("Lives", psize.width-80, 20);
  845.     offgraphics.drawString (Integer.toString (playerLives),
  846.         psize.width-30, 20);
  847.     if (playerLives < 1) offgraphics.drawString ("Game Over",
  848.         (psize.width>>1)-30, psize.height>>1);
  849.     g.drawImage (offscreen, 0, 0, null); 
  850. }
  851.  
  852.  
  853. /*
  854.  * Start the game thread
  855.  */
  856. public void start() {
  857.  
  858.     theThread = new Thread (this);
  859.     theThread.start ();
  860. }
  861.  
  862. /*
  863.  * Stop the game thread
  864.  */
  865. public void stop() {
  866.  
  867.     if (theThread != null)
  868.        theThread = null;
  869. }
  870. public void mouseClicked(MouseEvent e){}
  871. public void mouseEntered(MouseEvent e){}
  872. public void mouseExited(MouseEvent e){}
  873.  
  874. public void mouseReleased(MouseEvent e){}
  875.  
  876. public void mouseMoved(MouseEvent e)
  877. {
  878.     int x =e.getX();
  879.     int y =e.getY();
  880.     player.x = x;
  881.     player.y = psize.height-45;
  882.     if (player.x < 20) player.x = 20;
  883.     if (player.x > psize.width-20) player.x = psize.width-20;
  884. }
  885.  
  886. public void mousePressed(MouseEvent e)
  887. {
  888.     player.fire ();
  889. }
  890.  
  891. public void mouseDragged(MouseEvent e) 
  892. {
  893. }
  894.  
  895. }
  896.  
  897. /*
  898.  * the applet class
  899.  */
  900. ///////////////////////////////////////////////////////////////
  901. ///////////////////////////////////////////////////////////////
  902. ///////////////////////////////////////////////////////////////
  903. public class InvaderApp extends Applet implements ActionListener
  904. {
  905.  
  906. /*
  907.  * the playfield instance
  908.  */
  909. Playfield panel;
  910.  
  911. Button btnNewGame;
  912.  
  913. /*
  914.  * temporary storage for images
  915.  */
  916. Image img[] = new Image[4];
  917.  
  918. /*
  919.  * the speed of the game
  920.  * the number of invaders in this round
  921.  */
  922. int speed, NInvadersInPlay;
  923.  
  924. /*
  925.  * Called when the applet is loaded
  926.  
  927. * Load the images
  928.  */
  929. public void init() {
  930.  
  931.     int i;
  932.     MediaTracker tracker = new MediaTracker (this);
  933.  
  934.     setLayout(new BorderLayout());
  935.  
  936.     panel = new Playfield (this);
  937.     add("Center", panel);
  938.     Panel p = new Panel();
  939.     add("South", p);
  940.     btnNewGame = new Button("New Game");
  941.     p.add(btnNewGame);
  942.     btnNewGame.addActionListener(this);
  943.  
  944.  
  945.     showStatus ("Getting Invader images...");
  946.     for (i=0; i<4; i+=1) {
  947.         img[i] = getImage (getDocumentBase(), "T"+(i+1)+".gif");
  948.         tracker.addImage (img[i], 0);
  949.     }
  950.  
  951.     try {
  952.         tracker.waitForID(0);
  953.     } catch (InterruptedException e) { }
  954.  
  955.         for (i=0; i<panel.MaxInvaders; i+=1) {
  956.         panel.invaders[i] = new Invader ();
  957.         panel.invaders[i].inplay = false;
  958.         panel.invaders[i].img[0] = img[0];
  959.         panel.invaders[i].img[1] = img[1];
  960.         panel.invaders[i].img[2] = img[2];
  961.         panel.invaders[i].img[3] = img[3]; 
  962.     }
  963.     panel.player = new Player ();
  964.  
  965.     showStatus ("Getting player images...");
  966.     panel.player.img1 = getImage (getDocumentBase(),"Player1.gif");
  967. panel.player.img2 = getImage (getDocumentBase(),"Player2.gif");
  968.  
  969.     tracker.addImage (panel.player.img1, 1);
  970.     tracker.addImage (panel.player.img2, 1);
  971.     try {
  972.         tracker.waitForID (1);
  973.     } catch (InterruptedException e) { }
  974.     showStatus ("Ready to play!");
  975. }
  976.  
  977. /*
  978.  * Start the action thread
  979.  */
  980. public void start() {
  981.  
  982.     panel.start();
  983. }
  984.  
  985. /*
  986.  * Stop the action thread
  987.  */
  988. public void stop() {
  989.  
  990.     panel.stop();
  991. }
  992.  
  993. public void actionPerformed(ActionEvent ev)
  994. {
  995.         speed = 10;
  996.         panel.player.inplay = true;
  997.         panel.playerLives = 3;
  998.         panel.score = 0;
  999.         panel.playLevel = 1;
  1000.         NInvadersInPlay = 2 * panel.playLevel + 1;
  1001.         panel.NInvaders = NInvadersInPlay;
  1002.         for (int i=0; i<panel.NInvaders; i+=1)
  1003.             panel.invaders[i].random (speed,
  1004.                 panel.psize.width, panel.psize.height);
  1005.  
  1006.         play (getCodeBase(), "gong.au");
  1007.         if (NInvadersInPlay >= panel.MaxInvaders)
  1008.             NInvadersInPlay = panel.MaxInvaders;
  1009. }
  1010.  
  1011. /**
  1012.  * Play the appropriate sound when something is hit
  1013.  * @param which - which sound to play
  1014.  */
  1015. public void hit (int which) {
  1016.  
  1017.     switch (which) {
  1018.         case Playfield.INVADER_HIT:
  1019.         NInvadersInPlay -= 1;
  1020.         if (NInvadersInPlay < 1) {
  1021.             play (getCodeBase(), "gong.au");
  1022.             panel.playLevel += 1;
  1023.             NInvadersInPlay = 2 * panel.playLevel + 1;
  1024.             speed += 4;
  1025.             panel.NInvaders = NInvadersInPlay;
  1026.             for (int i=0; i<panel.NInvaders; i+=1)
  1027.             panel.invaders[i].random (speed,
  1028.                 panel.psize.width, panel.psize.height);
  1029.         } else {
  1030.             play (getCodeBase(), "drip.au");
  1031.         }
  1032.         break;
  1033.  
  1034.         case Playfield.PLAYER_HIT:
  1035.         play (getCodeBase(), "doh2.au");
  1036.         break;
  1037.     }
  1038. }
  1039. }
  1040.  
  1041.  
  1042.  
  1043.  
  1044.  
  1045.  
  1046.  
  1047. BallSpin.java:
  1048.  
  1049. import java.applet.*;
  1050. import java.awt.*;
  1051. import java.net.*;
  1052.  
  1053. /*
  1054.  * the applet class
  1055.   */
  1056. public class BallSpin extends Applet implements Runnable {
  1057.  
  1058. /*
  1059.  * the number of sub-images in the entire image
  1060.  */
  1061. int nImages;
  1062.  
  1063. /*
  1064.  * the full-size image
  1065.  */
  1066. Image theImage;
  1067.  
  1068. /*
  1069.  * the animation thread
  1070.  */
  1071. Thread thread;
  1072.  
  1073. /*
  1074.  * the position of the displayed image
  1075.  */
  1076. int xOffset;
  1077. int yOffset;
  1078.  
  1079. /*
  1080.  * offscreen image for double-buffering
  1081.  */
  1082. Image offImage;
  1083.  
  1084. /*
  1085.  * graphics object associated with the offscreen image
  1086.  */
  1087. Graphics offg;
  1088.  
  1089. /*
  1090.  * dimension of the offscreen image
  1091.  */
  1092. Dimension offSize;
  1093.  
  1094. /*
  1095.  * the sub-image to be drawn
  1096.  */
  1097. int whichImage;
  1098.  
  1099. /*
  1100.  * the dimension of each sub-image
  1101.  */
  1102. Dimension imageDim = new Dimension ();
  1103.  
  1104. /*
  1105.  * Initializes the applet
  1106.  * Loads the entire image
  1107.  */
  1108. public void init () {
  1109.  
  1110.     int i;
  1111.  
  1112.     thread = null;
  1113.  
  1114.     offSize = getSize ();
  1115.     offImage = createImage (offSize.width, offSize.height);
  1116.     offg = offImage.getGraphics ();
  1117.  
  1118.     nImages = 7;
  1119.     imageDim.width = 48;
  1120.     imageDim.height = 53;
  1121.  
  1122.     MediaTracker tracker = new MediaTracker (this);
  1123.  
  1124.         String name = "ballspin.gif";
  1125.     theImage = getImage (getDocumentBase(), name);
  1126.  
  1127.     tracker.addImage (theImage, 100);
  1128.     showStatus ("Getting image: "+name);
  1129.     try {
  1130.         tracker.waitForID (100);
  1131.     } catch (InterruptedException e) { }
  1132.  
  1133.     xOffset = nImages * 30;
  1134.     yOffset = 3 + offSize.height - imageDim.height;
  1135.     whichImage = nImages; 
  1136.     repaint ();
  1137.     thread = new Thread (this);
  1138.     thread.start ();
  1139. }
  1140.  
  1141. /*
  1142.  * Start the animation
  1143.  */
  1144. public void start () {
  1145.  
  1146.     xOffset = nImages * 30;
  1147.     yOffset = 3 + offSize.height - imageDim.height;
  1148.     whichImage = nImages;
  1149.     if (thread != null)
  1150.        thread = null;
  1151.     thread = new Thread (this);
  1152.     thread.start ();
  1153. }
  1154.  
  1155. /*
  1156.  * Stop the animation
  1157.  */
  1158. public void stop ()
  1159. {
  1160.     if (thread != null)
  1161.        thread = null;
  1162. }
  1163.  
  1164. /**
  1165.  * call update for efficiency
  1166.  * @param g - destination graphics object
  1167.  */
  1168. public void paint (Graphics g) {
  1169.  
  1170.     update (g);
  1171. }
  1172.  
  1173. /**
  1174.  * draw the sub-image at xOffset, yOffset
  1175.  * @param g - destination graphics object
  1176.  */
  1177. public void update (Graphics g) {
  1178.  
  1179.     Graphics offgClip;
  1180.  
  1181.     offg.setColor (Color.white);
  1182.     offg.fillRect (0, 0, offSize.width, offSize.height);
  1183.     offgClip = offg.create (xOffset, yOffset, imageDim.width,
  1184.         imageDim.height);
  1185.     offgClip.drawImage (theImage, 0 - (whichImage * imageDim.width),
  1186. 0, this);
  1187.     g.drawImage (offImage, 0, 0, this);
  1188. }
  1189.  
  1190. /*
  1191.  * Animation thread forces repaint every 100ms
  1192.  */
  1193. public void run () {
  1194.  
  1195.     int i;
  1196.  
  1197.     for (i=0; i<nImages; i+=1) {
  1198.         xOffset -= 30;
  1199.         whichImage -= 1;
  1200.         repaint ();
  1201.         try {
  1202.             Thread.sleep (100);
  1203.         } catch (InterruptedException e) { }
  1204.     }
  1205. }
  1206. }
  1207.  
  1208.  
  1209.  
  1210.  
  1211.  
  1212.