import java.awt.*; import java.applet.Applet; public class Water extends java.applet.Applet implements Runnable { Thread killme = null; ImageCanvas board; public void init() { // setLayout() is a java.awt.Container member. It sets the LayoutManager // for the container. Without it, the ImagePanels would get different // relative positions when the viewer is resized. setLayout(new BorderLayout()); // Place the ImageHelp at the top of the applet. ImageHelp imHelp = new ImageHelp(); add("North", imHelp); // Place the ImagePanel at the center of the applet. ImagePanel ip = new ImagePanel(this, imHelp.getLabel()); add("Center", ip); board = ip.getBoard(); } public void run() { while (killme != null) { try {Thread.sleep(100);} catch (InterruptedException e){} board.tick(); } killme = null; } public void start() { if (killme == null) { killme = new Thread(this); killme.start(); } } public void stop() { killme = null; } } class ImageHelp extends Panel { Label l; public ImageHelp() { setLayout(new GridLayout(2, 1)); // Create a new label, centered in the panel add(new Label("Move the tuber using the arrow keys", Label.CENTER)); l = new Label("Score: "); add(l); } public Label getLabel() { return l; } } class ImagePanel extends Panel { ImageCanvas board; public ImagePanel(Applet app, Label l) { // Set the layout so that it is one column full size of the panel // setLayout(new GridLayout(0, 1)); board = new ImageCanvas(app, l); add(board); } public ImageCanvas getBoard() { return board; } } class ImageCanvas extends Canvas /*implements ImageObserver*/ { int banks[][] = new int [2][12]; int xpos = 50, ypos = 50; int yOff = 0; int ySpeed = 1; Image im; Graphics gOff; Image imTuber; Image imFin; int xFins[] = new int[3]; int yFins[] = new int[3]; int xSpeedFin[] = new int[3]; int nShoreTick = 0; int nScore = 0; Label labelScore; boolean fPaused = true; boolean fDead = false; Image imCactus; int xCactus[] = new int[4]; int yCactus[] = new int[4]; public ImageCanvas(Applet app, Label l) { labelScore = l; imTuber = app.getImage(app.getDocumentBase(), "tuber.gif"); imFin = app.getImage(app.getDocumentBase(), "fin.gif"); imCactus = app.getImage(app.getDocumentBase(), "cactus.gif"); initBoard(); } void initBoard() { // Initialize the banks for (int i = 0; i < 12; i++) { for (int j = 0; j < 2; j++) { banks[j][i] = (int)(Math.random() * 30); } } // Initialize the cacti for (int i = 0; i < 4; i++) xCactus[i] = -999; // Initialize the sharks for (int i = 0; i < 3; i++) xFins[i] = -999; xpos = 100; ypos = 50; yOff = 0; ySpeed = 1; nShoreTick = 0; nScore = 0; fDead = false; } public void layout() { Rectangle r = bounds(); // @@@ Has this been set yet? im = createImage(r.width, r.height); gOff = im.getGraphics(); } // @@@ Is this member necessary? public void update(Graphics g) { paint(g); } public void paint(Graphics g) { Rectangle r = bounds(); // @@@ Has this been set yet? paintApplet(gOff); g.drawImage(im, 0, 0, this); } public void paintApplet(Graphics g) { Rectangle r = bounds(); g.setColor(Color.blue); g.fillRect(0, 0, r.width, r.height); // @@@ Can't use clearRect() 'cause I can't figure out how to set the background color... // g.clearRect(0, 0, r.width, r.height); // Draw the banks Polygon p1 = new Polygon(); p1.addPoint(0, 0); Polygon p2 = new Polygon(); p2.addPoint(r.width, 0); for (int i = 0; i < 12; i++) { p1.addPoint(banks[0][i], i * r.height / 10 - yOff); p2.addPoint(r.width - banks[1][i], i * r.height / 10 - yOff); } p1.addPoint(0, r.height); p1.addPoint(0, 0); p2.addPoint(r.width, r.height); p2.addPoint(r.width, 0); g.setColor(Color.yellow); g.fillPolygon(p1); g.fillPolygon(p2); // Draw the cacti for (int i = 0; i < 4; i++) if (xCactus[i] != -999) { // System.out.println("Drawing a cactus"); g.drawImage(imCactus, xCactus[i], yCactus[i], this); } // Draw the sharks for (int i = 0; i < 3; i++) if (xFins[i] != -999) g.drawImage(imFin, xFins[i], yFins[i], this); // Draw the player g.drawImage(imTuber, xpos, ypos, this); // Display any status messages g.setColor(Color.white); if (fDead) g.drawString("Press space bar for new game", 50, 50); else if (fPaused) g.drawString("Press space bar to tube", 50, 50); } int leftbank(int y) { Rectangle r = bounds(); int segment = (y + yOff) * 10 / r.height; return Math.max(banks[0][segment], banks[0][segment+1]); } int rightbank(int y) { Rectangle r = bounds(); int segment = (y + yOff) * 10 / r.height; return r.width - Math.min(banks[1][segment], banks[1][segment+1]); } public synchronized boolean handleEvent(Event e) { switch (e.id) { case Event.KEY_ACTION: case Event.KEY_PRESS: switch (e.key) { case Event.UP: case 'k': if (ypos - 5 > 0 && !fPaused) ypos -= 5; repaint(); return true; case Event.DOWN: case 'j': if (ypos + 5 < bounds().height - 32 && !fPaused) ypos += 5; repaint(); return true; case Event.RIGHT: case 'l': if (xpos + 5 < rightbank(ypos) - 32 && !fPaused) xpos += 5; repaint(); return true; case Event.LEFT: case 'h': if (xpos - 5 > leftbank(ypos) && !fPaused) xpos -= 5; repaint(); return true; // case 'z': // if (ySpeed > 0) // ySpeed--; // return true; // case 'x': // if (ySpeed < 10) // ySpeed++; // return true; case ' ': if (fDead) { initBoard(); fPaused = false; labelScore.setText("Score: " + String.valueOf(nScore)); } else fPaused = !fPaused; return true; default: return false; } default: return false; } } // tick() is because I couldn't figure out if I made this class Runnable what // whould I do about start()&stop() public void tick() { if (fPaused) return; // Scroll the shore yOff += ySpeed; // Scroll the player if (ypos-ySpeed > 0) { ypos -= ySpeed; } if (xpos < leftbank(ypos)) xpos = leftbank(ypos); else if (xpos > rightbank(ypos) - 32) xpos = rightbank(ypos) - 32; // Scroll the cactus for (int i = 0; i < 4; i++) if (xCactus[i] != -999) { yCactus[i] -= ySpeed; if (yCactus[i] < 0) { // System.out.println("Killing a cactus"); xCactus[i] = -999; } } Rectangle rectPlayer = new Rectangle(xpos+4, ypos+4, 32-4, 32-4); Rectangle rectShark = new Rectangle(); // Scroll the sharks for (int i = 0; i < 3; i++) { yFins[i] -= ySpeed; if (xFins[i] != -999 && (yFins[i] < 0 || xFins[i] < leftbank(yFins[i]))) { // Shark is off-screen. Destroy. // System.out.println("Destroyed a shark"); xFins[i] = -999; } if (xFins[i] != -999) { xFins[i] -= xSpeedFin[i] * ySpeed; // Did the shark hit the player? rectShark.reshape(xFins[i]+8, yFins[i]+8, 32-8, 32-8); if (rectPlayer.intersects(rectShark)) { fDead = true; fPaused = true; } } } // Update score, if on the bottom half of screen Rectangle r = bounds(); if (ypos+yOff > r.height/2) { nScore += ySpeed; labelScore.setText("Score: " + String.valueOf(nScore)); } // Do we need to generate another shore coordinate? if (yOff >= r.height/10) { yOff -= r.height/10; for (int i = 1; i < 12; i++) { banks[0][i-1] = banks[0][i]; banks[1][i-1] = banks[1][i]; } // banks[0][11] = banks[0][10] + 10; // banks[1][11] = banks[0][10] + 10; banks[0][11] = banks[0][10] + (int)(Math.random() * 20) - 7; banks[1][11] = banks[1][10] + (int)(Math.random() * 20) - 7; if (banks[0][11] < 0) banks[0][11] = 0; if (r.width - banks[1][11] < 100) banks[1][11] -= 64; if (banks[0][11] >= r.width) banks[0][11] = r.width-1; if (banks[1][11] >= r.width) banks[1][11] = r.width-1; if (banks[0][11] > banks[1][11]) { int i = banks[0][11]; banks[0][11] = banks[1][11]; banks[1][11] = i; } if (banks[0][11] + 64 > r.width - banks[1][11]) { banks[0][11] = r.width - banks[1][11] - 40; banks[1][11] -= 22; } // If necessary, generate a new shark for (int i = 0; i < 3; i++) if (xFins[i] == -999 && Math.random() < 0.2) { xFins[i] = r.width - banks[1][11] - 32; yFins[i] = 9 * r.height / 10; xSpeedFin[i] = (int)(Math.random() * 2) + 1; // System.out.println("Created a shark"); break; } nShoreTick++; if (nShoreTick > 20) { // System.out.println("Finished level " + String.valueOf(ySpeed)); nShoreTick = 0; banks[0][11] = 0; banks[1][11] = 0; if (ySpeed < 10) ySpeed++; } } // Add any needed cacti for (int i = 0; i < 4; i++) if (xCactus[i] == -999 && Math.random() < .02) { // System.out.println("Making a cactus"); yCactus[i] = r.height; if (Math.random() < 0.5) xCactus[i] = (int)(Math.random() * banks[0][11]); else xCactus[i] = r.width - (int)(Math.random() * banks[1][11]); } repaint(); } }