/** * @JDLunarLander.java * @version 1.2, 27 May 1998 * @author: John Donohue * * This is the classic Lunar Lander Game. * * Example of APPLET code: * * * */ import java.awt.*; import java.applet.*; import java.util.*; import java.net.*; /** * The Applet. */ public class JDLunarLander extends Applet implements Runnable { private static AudioClip mainThrusterSound; private static AudioClip attitudeThrusterSound; private static AudioClip crashSound; private static AudioClip landingSound; private Image bufferImage; //private Image blankImage; private LanderCanvas lCanvas; private Graphics bufferGraphics; //private Graphics blankGraphics; private Thread animate; private boolean runAnimation; private boolean zoomed; private Vector Lines; private Vector LandingPadLines; private int frameRate; private double scale; private double XDisplacement; private double YDisplacement; private Lander theLander; private int rightScrollEdge; private int leftScrollEdge; private int topScrollEdge; private int bottomScrollEdge; private int leftScreenEdge; private int rightScreenEdge; private int topScreenEdge; private int bottomScreenEdge; private int screenWidth; private int screenHeight; private long saveTimeAttitudeThrusterSoundStarted; private long saveTimeMainThrusterSoundStarted; private Panel playFieldPanel; private Panel controlPanel; private VertProgressBar fuelGuage; private Panel gravitySettingPanel; private CheckboxGroup gravitySettingRadio; private Checkbox moonGravityRadio, earthGravityRadio, jupiterGravityRadio; private int score; private Label lScore; private long saveTimeWeLandedOrCrashed; private Font lCanvasFont; private FontMetrics lCanvasFontMetrics; private Font pointsFont; Line l; LandingPadLine lp; Label l3, l4, l5; private String pointsMessage; private Panel p1; /** * The Applet. */ public void init() { Lines = new Vector(100); LandingPadLines = new Vector(100); double [][] landscapeArray = { {-1000d,-1000d}, {-1000d,-100d}, { 0d, 0d}, { 42d, 188d}, { 65d, 153d}, { 126d, 153d}, { 136d, 167d}, { 186d, 224d}, { 251d, 144d}, { 304d, 144d}, { 307d, 88d}, { 335d, 70d}, { 370d, 234d}, { 417d, 234d}, { 467d, 146d}, { 476d, 164d}, { 521d, 164d}, { 536d, 144d}, { 593d, 185d}, { 644d, 129d}, { 723d, 129d}, { 772d, 239d}, { 828d, 239d}, { 863d, 106d}, { 897d, 106d}, { 936d, 210d}, { 988d, 210d}, { 1026d, 90d}, { 1090d, 90d}, { 1133d, 155d}, { 1143d, 184d}, { 1120d, 216d}, { 1126d, 234d}, { 1165d, 234d}, { 1191d, 184d}, { 1227d, 141d}, { 1278d, 127d}, { 1316d, 127d}, { 1340d, 161d}, { 1435d, 126d}, { 1468d, 126d}, { 1494d, 0d}, { 2500d,-100d}, { 2500d,-1000d} }; double [][] landingPadArray = { { 65d, 152d, 126d, 152d, 10d }, { 251d, 143d, 304d, 143d, 20d }, { 370d, 233d, 417d, 233d, 20d }, { 476d, 163d, 521d, 163d, 25d }, { 644d, 128d, 723d, 128d, 30d }, { 772d, 238d, 828d, 238d, 35d }, { 863d, 105d, 897d, 105d, 40d }, { 936d, 209, 988d, 209d, 45d }, { 1026d, 89d, 1090d, 89d, 50d }, { 1126d, 233d, 1165d, 233d, 100d}, { 1278d, 126d, 1316d, 126d, 60d }, { 1435d, 125d, 1468d, 125d, 65d } }; bufferImage = createImage(bounds().width - 50, bounds().height); bufferGraphics = bufferImage.getGraphics(); bufferGraphics.setColor(Color.white); pointsFont = new Font ( "Helvetica", Font.PLAIN, 16); lCanvasFont = new Font ( "Helvetica", Font.PLAIN, 20); lCanvas = new LanderCanvas(bufferImage); lCanvasFontMetrics = bufferGraphics.getFontMetrics(lCanvasFont); for (int i = 0; i < landingPadArray.length - 1; i++) { LandingPadLines.addElement( new LandingPadLine( landingPadArray[i][0], landingPadArray[i][1], landingPadArray[i][2], landingPadArray[i][3], landingPadArray[i][4], bufferGraphics ) ); } for (int i = 0; i < landscapeArray.length - 1; i++) { Lines.addElement( new Line( landscapeArray[i][0], landscapeArray[i][1], landscapeArray[i+1][0], landscapeArray[i+1][1] ) ); } screenWidth = bufferImage.getWidth(null); screenHeight = bufferImage.getHeight(null); leftScreenEdge =0; rightScreenEdge = screenWidth; topScreenEdge = 0; bottomScreenEdge = screenHeight; rightScrollEdge = screenWidth -100; leftScrollEdge = 100; topScrollEdge = 50; bottomScrollEdge = screenHeight -50; setLayout( new BorderLayout() ); controlPanel = new Panel(); controlPanel.setBackground(Color.white); controlPanel.setLayout( null); controlPanel.resize(50,screenHeight); Font f1 = new Font ( "Helvetica", Font.PLAIN, 12); Font f2 = new Font ( "Helvetica", Font.BOLD, 10); Font f3 = new Font ( "Helvetica", Font.PLAIN, 9); Font f4 = new Font ( "Helvetica", Font.BOLD, 16); Font f5 = new Font ( "Helvetica", Font.BOLD, 12); Font f6 = new Font ( "Helvetica", Font.BOLD, 14); Label l1 = new Label("Lunar ", Label.LEFT); l1.setForeground(Color.black); l1.setFont(f5); l1.reshape(7,8,48,12); controlPanel.add(l1); Label l2 = new Label("Lander", Label.CENTER); controlPanel.add(l2); l2.setForeground(Color.black); l2.setFont(f5); l2.reshape(0,23,48,12); Label l6 = new Label("Score"); l6.setFont(f6); l6.reshape(7,40,48,15); controlPanel.add(l6); lScore = new Label("0"); lScore.setForeground(Color.red); lScore.setFont(f4); lScore.reshape(7,55,48,15); controlPanel.add(lScore); Label lFuel = new Label("Fuel"); lFuel.setFont(f4); lFuel.reshape(10,79,48,15); controlPanel.add(lFuel); fuelGuage = new VertProgressBar(20, 50, Color.gray, Color.green, Color.black); fuelGuage.reshape(15,95,20,50); controlPanel.add(fuelGuage); Label l7 = new Label("Gravity"); l7.setFont(f5); l7.reshape(5,161,48,12); controlPanel.add(l7); gravitySettingPanel = new Panel(); gravitySettingPanel.setLayout( null); gravitySettingPanel.setBackground(Color.white); gravitySettingPanel.setForeground(Color.black); gravitySettingPanel.resize(50,70); Label gravityLabel = new Label("Gravity"); gravityLabel.setFont(f1); gravityLabel.reshape(4,0,46,12); gravityLabel.setForeground(Color.darkGray); gravitySettingRadio = new CheckboxGroup(); moonGravityRadio = new Checkbox("Moon", gravitySettingRadio, true); earthGravityRadio = new Checkbox("Earth", gravitySettingRadio, false); jupiterGravityRadio = new Checkbox("Jupiter", gravitySettingRadio, false); moonGravityRadio.setFont(f3); earthGravityRadio.setFont(f3); jupiterGravityRadio.setFont(f3); gravitySettingPanel.add(moonGravityRadio); gravitySettingPanel.add(earthGravityRadio); gravitySettingPanel.add(jupiterGravityRadio); moonGravityRadio.reshape(2,0,48,12); earthGravityRadio.reshape(2,12,48,12); jupiterGravityRadio.reshape(2,24,48,12); controlPanel.add(gravitySettingPanel); gravitySettingPanel.reshape(0,175,50,70); l3 = new Label("John"); l3.setForeground(Color.blue); l3.setFont(f3); l3.reshape(16,218,50,9); controlPanel.add(l3); l4 = new Label("Donohue's"); l4.setFont(f3); l4.reshape(4,228,50,9); l4.setForeground(Color.blue); controlPanel.add(l4); l5 = new Label("Web Page"); l5.setFont(f3); l5.reshape(4,238,50,9); l5.setForeground(Color.blue); controlPanel.add(l5); add("West", controlPanel); add("Center",lCanvas); super.init(); mainThrusterSound = null; attitudeThrusterSound = null; landingSound = null; crashSound = null; crashSound = getAudioClip( getDocumentBase(), "crash.au"); crashSound.play(); crashSound.stop(); mainThrusterSound = getAudioClip( getDocumentBase(), "mainThruster.au"); mainThrusterSound.play(); mainThrusterSound.stop(); attitudeThrusterSound = getAudioClip( getDocumentBase(), "attitudeThruster.au"); attitudeThrusterSound.play(); attitudeThrusterSound.stop(); landingSound = getAudioClip( getDocumentBase(), "landed.au"); landingSound.play(); landingSound.stop(); runAnimation = false; newGame(); } public void start() { lCanvas.requestFocus(); saveTimeAttitudeThrusterSoundStarted =0L; saveTimeMainThrusterSoundStarted =0L;; XDisplacement = 0d; YDisplacement = 0d; scale =1d; zoomed = false; frameRate = 15; initAnimation(); if (animate == null) { animate = new Thread (this); animate.start(); } } /** * initAnimation */ public void initAnimation() { repaint(); } /** * Run */ public void run() { for (;;) { try { handleSounds(); Thread.sleep(15); bufferGraphics.setColor(Color.black); bufferGraphics.fillRect(0, 0, bounds().width, bounds().height); bufferGraphics.setColor(Color.white); if (!theLander.crashed) { fuelGuage.updateBar(theLander.fuel); if (theLander.fuel < .15) fuelGuage.setProgressColor(Color.red); else fuelGuage.setProgressColor(Color.green); if ( theLander.screenPosX > rightScrollEdge ) XDisplacement = theLander.landscapePosX - ( rightScrollEdge / scale); if (theLander.screenPosX < leftScrollEdge ) XDisplacement = theLander.landscapePosX - (leftScrollEdge / scale); if ( theLander.screenPosY < topScrollEdge ) YDisplacement = theLander.landscapePosY - (topScrollEdge / scale); if (theLander.screenPosY > bottomScrollEdge ) YDisplacement = theLander.landscapePosY - (bottomScrollEdge / scale); } for (int ktr =0; ktr < Lines.size(); ktr++ ) { l = (Line)Lines.elementAt(ktr); l.calculateScreenCoordinates(XDisplacement, YDisplacement, scale); l.drawLine(bufferGraphics); } bufferGraphics.setFont(pointsFont); for (int ktr =0; ktr < LandingPadLines.size(); ktr++ ) { l = (Line)LandingPadLines.elementAt(ktr); l.calculateScreenCoordinates(XDisplacement, YDisplacement, scale); l.drawLine(bufferGraphics); } bufferGraphics.setColor(Color.white); if (!theLander.landed) theLander.move(); //Over Landing Pad Detect zoomed = false; for (int ktr =0; ktr < LandingPadLines.size(); ktr++ ) { l = (Line)LandingPadLines.elementAt(ktr); if ( (theLander.landscapePosX > (l.startX - 25)) && (theLander.landscapePosX < (l.endX + 25)) && (theLander.landscapePosY > (l.startY - 50)) && (theLander.landscapePosY < l.endY) ) { zoomed = true; continue; } } if (zoomed && scale == 1d) changeScale(2); if (!zoomed && scale == 2d) changeScale(1); //Landing Detect if (!theLander.crashed && !theLander.landed) { for (int ktr =0; ktr < LandingPadLines.size(); ktr++ ) { lp = (LandingPadLine)LandingPadLines.elementAt(ktr); if ( ( lp.collisionDetect((Line)theLander.landerLines.elementAt(20)) || lp.collisionDetect((Line)theLander.landerLines.elementAt(14)) ) && ( theLander.attitude == 0 ) ) { if ( (theLander.deltaY < theLander.maxSafeLandingSpeed ) && ( Math.abs(theLander.deltaX) < theLander.maxSafeLandingSpeed) ) { theLander.landed = true; saveTimeWeLandedOrCrashed = System.currentTimeMillis(); if ( lp.landedHereAlready ) pointsMessage = "Landed here already, No Points"; else { theLander.fuel = theLander.fuel + .5f; if (theLander.fuel > 1f) theLander.fuel = 1f; landingSound.play(); lp.landedHereAlready = true; score = score + lp.pointsScored; displayScore(); pointsMessage = "Scored " +Integer.toString(lp.pointsScored) + " points"; } break; } } } } //Collision Detect collisionDetect: if (!theLander.crashed && !theLander.landed) { for (int ktr =0; ktr < theLander.landerLines.size(); ktr++ ) { for (int ktr2 =0; ktr2 < Lines.size(); ktr2++ ) { l = (Line)Lines.elementAt(ktr2); if (l.collisionDetect((Line)theLander.landerLines.elementAt(ktr)) ) { //bufferGraphics.setColor(Color.green); explodeLander(); break collisionDetect; } } } } if (theLander.landed) { bufferGraphics.setFont(lCanvasFont); bufferGraphics.drawString("Landed Sucessfully !", (screenWidth - (lCanvasFontMetrics.stringWidth("Landed Sucessfully !"))) /2 ,100); bufferGraphics.drawString(pointsMessage, (screenWidth - (lCanvasFontMetrics.stringWidth(pointsMessage))) /2 ,130); } if ( System.currentTimeMillis() > saveTimeWeLandedOrCrashed + 3000 ) { bufferGraphics.setFont(lCanvasFont); if (theLander.crashed) bufferGraphics.drawString("Press Any Key to Play Again", (screenWidth - (lCanvasFontMetrics.stringWidth("Press Any Key to Play Again"))) /2 ,100); if (theLander.landed) bufferGraphics.drawString("Press T to Take Off Again", (screenWidth - (lCanvasFontMetrics.stringWidth("Press T to Take Off Again"))) /2 ,160); } theLander.draw(bufferGraphics, XDisplacement, YDisplacement, scale); // bufferGraphics.drawImage(bufferImage, 0, 0, null); lCanvas.repaint(); repaint(); } catch(InterruptedException e) { return; }; } } /** * launchLander */ public void launchLander() { theLander.deltaY = -.15; theLander.landed = false; } /** * explodeLander */ public void explodeLander() { if (!theLander.crashed) { saveTimeWeLandedOrCrashed = System.currentTimeMillis(); theLander.crashed = true; theLander.setExplosionDeltas(); crashSound.play(); } } /** * stop */ public void stop() { if (animate != null) { animate.stop(); animate=null; } } /** * update */ public void update(Graphics g) { paint(g); } /** * paint */ public void paint(Graphics g) { g.setColor(Color.red); g.fillRect(0, 0, bounds().width, bounds().height); } /** * */ public void changeScale(double scaleIn) { scale = scaleIn; XDisplacement = theLander.landscapePosX - ( (screenWidth/2) / scale); YDisplacement = theLander.landscapePosY - ( (screenHeight/2) / scale); } /** * */ public boolean keyUp(Event evt, int key) { if ( key == ' ') { theLander.mainRocketOff(); saveTimeAttitudeThrusterSoundStarted =0; } return false; } /** * */ public boolean keyDown(Event evt, int key) { if ( key == 's') System.out.println("Score = " + Integer.toString(score)); if ( (key == 'T' || key == 't') && theLander.landed ) { if ( System.currentTimeMillis() > (saveTimeWeLandedOrCrashed + 3000) ) launchLander(); } if (theLander.crashed) { if ( System.currentTimeMillis() > saveTimeWeLandedOrCrashed + 3000 ) newGame(); } if ( !theLander.crashed && !theLander.landed ) { if ( key == ' ') { theLander.mainRocketOn(); } if ( key == Event.LEFT) { theLander.spinLanderLeft(); attitudeThrusterSound.play(); } if ( key == Event.RIGHT) { theLander.spinLanderRight(); attitudeThrusterSound.play(); } } return false; } /** * */ public boolean mouseDown(Event evt, int x, int y) { //System.out.println("X=" + Integer.toString(x) + " Y=" + Integer.toString(y) ); if ( y > 218 && x < 50 ) { try { URL urlToGoto = new URL( getCodeBase(), "http://www.panix.com/~wizjd" ); getAppletContext().showDocument(urlToGoto); } catch (MalformedURLException e) { e.printStackTrace(); } } return false; } /** * */ public boolean action(Event evt, Object o) { if (evt.target instanceof Checkbox) { lCanvas.requestFocus(); newGame(); start(); } return false; } /** * */ public void handleSounds() { if ( theLander.mainRocketOperating) { if ( System.currentTimeMillis() > saveTimeAttitudeThrusterSoundStarted + 5000) { mainThrusterSound.play(); saveTimeAttitudeThrusterSoundStarted = System.currentTimeMillis(); } } else mainThrusterSound.stop(); } public void newGame() { score =0; displayScore(); theLander = new Lander(90, 75, .1d, -.1d); setLanderGravity(); Enumeration enum = LandingPadLines.elements(); while( enum.hasMoreElements() ) { ((LandingPadLine)enum.nextElement()).landedHereAlready = false;; } } public void setLanderGravity() { theLander.gravityAcceleration = ((double).003); //Default if ( moonGravityRadio.getState() ) { theLander.gravityAcceleration = ((double).003); scaleLandingPadPoints(1); } if ( earthGravityRadio.getState() ) { theLander.gravityAcceleration = ((double).006); scaleLandingPadPoints(2); } if ( jupiterGravityRadio.getState()) { theLander.gravityAcceleration = ((double).009); scaleLandingPadPoints(3); } } public void displayScore() { String tmpStr; tmpStr = "0000" + Integer.toString(score); lScore.setText(tmpStr.substring(tmpStr.length() - 4, tmpStr.length()) ); } /** * */ public void scaleLandingPadPoints(int multiplyPointsBy) { Enumeration enum = LandingPadLines.elements(); while( enum.hasMoreElements() ) { ((LandingPadLine)enum.nextElement()).scalePoints(multiplyPointsBy); } } }