1 // MicroNibbles - Nibbles in 150 Zeilen - (C)2002 Jörg Mensmann
  2 import java.awt.*;
  3 import java.awt.event.*;
  4 import java.awt.image.PixelGrabber;
  5 public class MicroNibbles extends java.applet.Applet implements Runnable, KeyListener {
  6     Thread thread = null;                     // Timer-Thread
  7     Image offscreen, backgroundimg;           // Bitmaps
  8     Graphics offgraphics;                     // Backbuffer-Graphic
  9     Font bigFont, mediumFont, smallFont;      // Schriftarten
 10     int direction, snake_len, snake_num, counter = 0, level = 1;
 11     boolean inGame, showCrash, hasWon, gameOver; // Spiellogik
 12     int[] snake_x, snake_y;      // Positionen der Einzelteile der Schlange
 13     int[][] field;               // Spielfeld
 14     final int FeldX = 64, FeldY = 40, // Größe der Spielfeldes
 15 	EMPTY = 0, OBSTACLE = 1, SNAKE = 2, NUMBER = 3, // für Spielfeld
 16 	NORTH = 0, EAST = 1, SOUTH = 2, WEST = 3;       // Richtungen
 17     public void init() {
 18 	backgroundimg = getImage(getDocumentBase(), getParameter("bg"));
 19 	bigFont = new Font("TimesRoman,Times", Font.BOLD, 30);
 20         mediumFont = new Font("TimesRoman,Times", 0, 20);     
 21         smallFont = new Font("Courier New,Courier,Helvetica", 0, 15); 
 22         snake_x = new int[70]; 
 23 	snake_y = new int[70];
 24         field = new int[FeldX + 1][FeldY + 1];
 25 	addKeyListener(this);
 26     }
 27     public void start() {
 28 	if (thread == null) {
 29 	    thread = new Thread(this);
 30 	    thread.start();
 31 	}
 32     }
 33     public void stop() { thread = null; }
 34     public void run() {          // Run-Methode des Thread
 35         while (thread != null) {
 36 	    try { Thread.sleep(80); } catch (InterruptedException e){}
 37 	    counter++;
 38 	    if (inGame) moveSnake();
 39 	    repaint();
 40         }
 41         thread = null;
 42     }
 43     void newNumber() { // Zahl irgendwo auf dem Spielfeld einfügen
 44         int x, y;
 45         do {
 46             x = (int)(Math.random() * (FeldX - 2)) + 1;
 47             y = (int)(Math.random() * (FeldY - 2)) + 1;
 48         } while (GetField(x, y) != EMPTY); // Leeres Feld suchen
 49         SetField(x, y, NUMBER);
 50     }
 51     int GetField(int x, int y) { return field[x][y]; }
 52     void SetField(int x, int y, int w) { field[x][y] = w; }
 53     void moveSnake() {
 54         SetField(snake_x[snake_len], snake_y[snake_len], EMPTY); // Ende der Schlange entfernen
 55         for (int i=snake_len; i >= 2; i--) { // Positionen weitersetzen
 56             snake_x[i] = snake_x[i - 1];
 57             snake_y[i] = snake_y[i - 1];
 58         }
 59         switch (direction) {  // Kopf neu setzen bzw. Crash
 60           case NORTH: if (snake_y[1] > 0) snake_y[1]--; else crash(); break;
 61           case EAST:  if (snake_x[1] < FeldX - 1) snake_x[1]++; else crash(); break;
 62           case SOUTH: if (snake_y[1] < FeldY - 1) snake_y[1]++; else crash(); break;
 63           case WEST:  if (snake_x[1] > 0) snake_x[1]--; else crash(); break;
 64         }
 65 	if (GetField(snake_x[1], snake_y[1]) == NUMBER) { // Nummer?
 66             if (--snake_num < 1) { // Level gewonnen?
 67 		inGame = !(hasWon = true); 
 68 		gameOver = (getParameter("level" + (++level)) == null);		    
 69 		if (gameOver) level = 1; 
 70 	    } else {
 71 		 newNumber(); // Neue Nummer und Länge der Schlange erhöhen
 72 		 for (int i=snake_len + 1; i <= (snake_len + 10 - snake_num); i++) {
 73 		     snake_x[i] = snake_x[snake_len];
 74 		     snake_y[i] = snake_y[snake_len];
 75 		 }
 76 		 snake_len += 10 - snake_num;
 77             }
 78         }
 79         if ((GetField(snake_x[1], snake_y[1]) != EMPTY) && (GetField(snake_x[1], snake_y[1]) != NUMBER)) crash(); 
 80 	  else SetField(snake_x[1], snake_y[1], SNAKE);
 81     }
 82     void crash () { showCrash = true; inGame = false; }
 83     public synchronized void update(Graphics g) {
 84         if (offscreen == null) { // Erster Durchlauf -> Backbuffer erzeugen
 85             offscreen = createImage(getSize().width, getSize().height);
 86             offgraphics = offscreen.getGraphics();
 87         }
 88 	offgraphics.drawImage(backgroundimg, 0, 0, null); // Hintergrund
 89         if ((inGame) || (showCrash)) {
 90 	    offgraphics.setColor(Color.red);  
 91 	    for (int x=0; x <= FeldX; x++)        // Hindernisse
 92 		for (int y=0; y <= FeldY; y++) 
 93 		    if (GetField(x, y) == OBSTACLE) offgraphics.fillRect(x*10, y*10, 10, 10);
 94 	    if (!showCrash || counter % 2 == 0) { // Wenn gecrashed dann blinkend darstellen
 95 		offgraphics.setColor(Color.green); 
 96 		for (int x=0; x <= FeldX; x++)    // Schlange 
 97 		    for (int y=0; y <= FeldY; y++)
 98 			if (GetField(x, y) == SNAKE) offgraphics.fillRect(x*10, y*10, 10, 10);
 99 	    }
100             offgraphics.setFont(smallFont);
101             offgraphics.setColor(Color.white);
102             for (int x=0; x <= FeldX; x++)        // Zahl
103                 for (int y=0; y <= FeldY; y++) 
104                     if (GetField(x, y) == NUMBER) offgraphics.drawString("" + snake_num, x*10, y*10 + 10);
105         }
106         if (!inGame) {        // Nicht im Spiel -> Text anzeigen
107             offgraphics.setColor(Color.black);
108             offgraphics.setFont(bigFont);
109             offgraphics.drawString("MicroNibbles", 10, 35);
110             offgraphics.setColor(Color.blue);
111             offgraphics.setFont(bigFont);
112 	    if (counter % 2 == 0 && showCrash) offgraphics.drawString("Crash!", 10, 75);
113   	      else if ((counter / 7) % 2 == 0 && hasWon) 
114                 offgraphics.drawString(gameOver ? "You win! - Game Over" : "Level complete!", 10, 75);
115 	    offgraphics.setFont(mediumFont);
116 	    offgraphics.drawString("Press SPACE to begin!", 10, 120);
117 	}
118         g.drawImage(offscreen, 0, 0, null);  // Backbuffer auf den Screen
119     }   
120     public void keyPressed(KeyEvent e) {
121         if (!inGame) {
122 	    if (e.getKeyCode() == KeyEvent.VK_SPACE) initGame();
123 	} else 
124         switch (e.getKeyCode()) {
125 	  case KeyEvent.VK_UP:    if (direction != SOUTH) direction = NORTH; break;
126 	  case KeyEvent.VK_DOWN:  if (direction != NORTH) direction = SOUTH; break;
127 	  case KeyEvent.VK_RIGHT: if (direction != WEST) direction = EAST; break;
128 	  case KeyEvent.VK_LEFT:  if (direction != EAST) direction = WEST; break;
129 	}
130     }
131     public void keyTyped(KeyEvent e) { }
132     public void keyReleased(KeyEvent e) { }
133     void initGame() { 
134 	int[] pixels = new int[FeldX * FeldY];
135 	Image levelimg = getImage(getDocumentBase(), getParameter("level" + level)); 
136 	PixelGrabber pg = new PixelGrabber(levelimg, 0, 0, FeldX, FeldY, pixels, 0, FeldX);
137 	try { pg.grabPixels(); } catch (InterruptedException e) { }
138 	for (int x=0; x < FeldX; x++)   // Level wird abhängig von
139           for (int y=0; y < FeldY; y++) // der Level-Grafik aufgebaut
140 	    SetField(x, y, (pixels[x + y*FeldX] != pixels[0]) ? OBSTACLE : EMPTY);
141         direction = 1; snake_num = 9; snake_len = 6; 
142         for (int i=1; i <= snake_len; i++) {
143 	    snake_x[i] = 20 - i;
144 	    snake_y[i] = 4;
145 	    SetField(20 - i, 4, SNAKE);
146         }
147         newNumber();
148         inGame = !(showCrash = hasWon = gameOver = false);
149     }
150 }


syntax highlighted by Code2HTML, v. 0.9.1