Benutzer-Werkzeuge

Webseiten-Werkzeuge


api:projects:snake:start

Unterschiede

Hier werden die Unterschiede zwischen zwei Versionen angezeigt.


Vorhergehende Überarbeitung
api:projects:snake:start [2025/06/29 05:51] (aktuell) – [Snake] martin
Zeile 1: Zeile 1:
 +====== Snake ======
 +<WRAP center round info 80%>
 +Das Computerspiel **Snake** gibt es bereits seit 1976 ([[https://en.wikipedia.org/wiki/Snake_(video_game_genre)|siehe den Wikipedia-Artikel dazu]]). Im folgenden findest Du zwei technisch sehr unterschiedliche Versionen, die beide mit den Pfeiltasten gesteuert werden:
 +  * In der ersten Version ist die Klasse ''Snake'' eine Unterklasse von ''Group'', die den Schlangenkörper in Form von lauter Kreisen enthält. Der Kopf ist ein rot gefärbter Kreis. Die Schlange kriecht, indem vorne ein neuer Kopf hinzugefügt wird, der alte Kopf hellblau gefärbt (und damit zu einem Körperstück) wird und am hinteren Ende ein Kreis entfernt wird.
 +  * In der zweiten Version füllt ein Objekt der Klasse ''Bitmap'' mit der Auflösung von 30x30 Punkten den kompletten Grafikausgabebereich. Jeder Punkt er Bitmap wird als Quadrat dargestellt, dessen Farbe man mit der Methode ''bitmap.setColor'' setzen und mit ''bitmap.getColor'' auslesen kann. Der Schlangenkörper besteht einfach nur aus gefärbten Punkten der Bitmap. Damit das jeweils letzte Schlangenglied gelöscht werden kann, muss die Schlange die Koordinaten aller ihrer Glieder (einschließlich des Kopfes) speichern. Dazu dienen die Arrays ''punkteX'' und ''punkteY''
 +Beide Programme sind nur sehr **unvollständige Projektvorlagen**. 
 +</WRAP>
  
 +===== 1. Version: Schlangenkörper aus Kreisen =====
 +<HTML>
 +<div class="java-online" style="height: 500px; width: 100%" data-java-online="{'withBottomPanel': true, 'id': 'Snake1', 'speed': 'max'}">
 +
 +<script type="text/plain" title="SnakeMain.java">
 +World w = new World(1000, 1000);
 +new SnakeMain();
 +
 +class SnakeMain extends Actor {
 +
 +   Snake snake;
 +   Group früchte = new Group();
 +
 +   Text großeAnzeige;
 +   Text kleineAnzeige;
 +
 +   Text punkteanzeige;
 +   int punkte;
 +
 +   String state;
 +
 +   public SnakeMain() {
 +      super();
 +
 +      punkteanzeige = new Text(5, 5, 64, "0");
 +      punkteanzeige.setFillColor("#ffffff");
 +      punkteanzeige.setBorderColor("#000000");
 +
 +      großeAnzeige = new Text(500, 300, 100, "Snake");
 +      großeAnzeige.setAlignment(Alignment.center);
 +      großeAnzeige.setFillColor("#fdb802");
 +      großeAnzeige.setBorderColor("#6d481a");
 +
 +      kleineAnzeige = großeAnzeige.copy();
 +      kleineAnzeige.move(0, 150);
 +      kleineAnzeige.setFontsize(50);
 +      kleineAnzeige.setText("Press Space to start");
 +
 +      setState("startscreen");
 +
 +   }
 +
 +   public void act() {
 +      if(Math.random() < 0.02 && state == "playing") {
 +         früchte.add(new Frucht(snake));
 +      }
 +
 +      Shape[] berührteFrüchte = früchte.getCollidingShapes(snake);
 +
 +      for(int i = 0; i < berührteFrüchte.length; i++) {
 +         snake.circlesToAdd += 3;
 +         berührteFrüchte[i].destroy();
 +         punkte++;
 +         zeigePunkte();
 +         Sound.playSound(Sound.short_digging);
 +      }
 +
 +      if(isKeyDown(" ")) {
 +         if(state == "startscreen" || state == "gameover") {
 +            setState("playing");
 +         }
 +      }
 +
 +   }
 +
 +   void zeigePunkte() {
 +      this.punkteanzeige.setText(punkte); 
 +   }
 +
 +   void setState(String stateNew) {
 +      if(stateNew == "gameover") {
 +         großeAnzeige.setText("Game over");
 +         großeAnzeige.setVisible(true);
 +         kleineAnzeige.setVisible(true);
 +         snake.stopActing();
 +         Sound.playSound(Sound.far_explosion);
 +      }
 +
 +      if(stateNew == "startscreen") {
 +         großeAnzeige.setText("Snake");
 +         großeAnzeige.setVisible(true);
 +         kleineAnzeige.setVisible(true);
 +      }
 +
 +      if(stateNew == "playing") {
 +         großeAnzeige.setVisible(false);
 +         kleineAnzeige.setVisible(false);
 +         if(snake != null) snake.destroy();
 +         snake = new Snake(this);
 +         punkte = 0;
 +      }
 +
 +      state = stateNew;
 +   }
 +
 +
 +}
 +</script>
 +
 +<script type="text/plain" title="Snake.java">
 +
 +
 +class Snake extends Group {
 +   
 +   SnakeMain snakeMain;
 +
 +   // Geschwindigkeit des Schlangenkopfs:
 +   int vx = 8;
 +   int vy = 0;
 +
 +   int circlesToAdd = 0;   // Falls Obst gegessen wurde: so viele Kreise kommen hinzu
 +
 +   int radius = 20;        // Radius der Kreise
 +
 +   Snake(SnakeMain snakeMain) {
 +      super();
 +      this.snakeMain = snakeMain;
 +
 +      // Kopf zur Gruppe hinzufügen:
 +      Circle head = new Circle(500, 500, radius);
 +      head.setFillColor(Color.red);
 +      add(head);
 +   }
 +
 +   public void act() {
 +      int v = 8;
 +      
 +      // Richtungsänderung auswerten:
 +      if(vx == 0) { 
 +         if(isKeyDown(Key.ArrowRight)) {
 +            vy = 0;
 +            vx = v;
 +         }
 +         if(isKeyDown(Key.ArrowLeft)) {
 +            vy = 0;
 +            vx = -v;
 +         }
 +      } else {
 +         if(isKeyDown(Key.ArrowUp)) {
 +            vy = -v;
 +            vx = 0;
 +         }
 +         if(isKeyDown(Key.ArrowDown)) {
 +            vy = v;
 +            vx = 0;
 +         }
 +      }
 +
 +      // Das letzte hinzugefügte Element ist der bisherige Kopf-Kreis
 +      Circle oldHead = (Circle)this.get(size() - 1);
 +
 +      // Neuen Kopf-Kreis erstellen und in Kriechrichtung verschieben:
 +      Circle newHead = oldHead.copy();
 +      newHead.move(vx, vy);
 +
 +      // Neuen Kopf zur Schlange hinzufügen:
 +      add(newHead);
 +
 +      // Aus dem akten Kopf wird durch Einfärben ein Schlangenglied:
 +      oldHead.setFillColor(Color.lightblue);
 +      oldHead.setAlpha(0.5);
 +
 +      // Hat die Schlange was gegessen?
 +      if(circlesToAdd == 0) {
 +         // Nein => Am Ende einen Kreis entfernen (da ja der neue Kopfkreis weiter oben hinzukam):
 +         Shape shapeToRemove = get(0);
 +         shapeToRemove.destroy();      // Zerstört den Kreis und entfernt ihn aus dem Group-Objekt
 +      } else {
 +         circlesToAdd--;
 +      }
 +
 +      /*
 +       * Der Kopfkreis berührt immer bis zu sieben Schlangenglieder hinter ihm. Falls er mehr
 +       * berührt, beißt sich die Schlange gerade selbst:
 +       */
 +      if(getCollidingShapes(newHead).length > 7 || newHead.isOutsideView()) {
 +         snakeMain.setState("gameover");
 +      }
 +
 +   }
 +
 +}
 +</script>
 +
 +<script type="text/plain" title="Frucht.java">
 +class Frucht extends Rectangle {
 +   
 +   int time = 0;
 +
 +   Frucht(Snake snake) {
 +      super(-10, -10, 1, 1);
 +
 +      do {
 +         moveTo(Math.random() * 900 + 50, Math.random() * 900 + 50);
 +      } while(snake.collidesWith(this));
 +
 +      rotate(45);
 +
 +      setFillColor(Color.fromHSL(Math.random()*360, 100, 80));
 +
 +   }
 +
 +   public void act() {
 +
 +      double d = Math.sin(Math.PI / 20 * time) * 6;
 +      setWidth(15 + d);
 +      setHeight(15 + d);
 +      time++;
 +   }
 +
 +
 +
 +}
 +</script>
 +
 +</div>
 +
 +</HTML>
 +
 +===== 2. Version: Grafikausgabe mit Bitmap =====
 +<HTML>
 +<div class="java-online" style="height: 500px; width: 100%" data-java-online="{'withBottomPanel': true, 'id': 'Snake2', 'speed': 'max'}">
 +
 +<script type="text/plain" title="SnakeMain.java">
 +new World(1000, 1000);
 +new SnakeMain();
 +
 +class SnakeMain extends Actor {
 +   
 +   Bitmap bitmap;
 +   Snake snake;
 +
 +   SnakeMain() {
 +      super();
 +      bitmap = new Bitmap(30, 30, 0, 0, 1000, 1000);
 +      bitmap.fillAll(0, 0);
 +      snake = new Snake(this);
 +   }
 +
 +   public void act() {
 +      if(Math.random() < 0.03) {
 +         int x = Math.floor(Math.random() * 31);
 +         int y = Math.floor(Math.random() * 31);
 +         bitmap.setColor(x, y, 0x00ff00);
 +      }
 +
 +   }
 +
 +
 +}
 +
 +</script>
 +
 +<script type="text/plain" title="Snake.java">
 +
 +
 +class Snake extends Actor {
 +   
 +   Bitmap bitmap;
 +   SnakeMain snakeMain;
 +
 +   // In diesem Array merken wir uns die Koordinaten der Schlangenglieder:
 +   int[] punkteX = new int[1000];
 +   int[] punkteY = new int[1000];
 +   int länge = 0;       // Aktuelle Länge der Schlange inklusive Kopf
 +
 +   int zeit = 0;        // Zählt die Zeit in 1/30-tel Sekunden
 +
 +   // Aktuelle Kriechrichtung der Schlange:
 +   int vx = 1; 
 +   int vy = 0;
 +
 +   Snake(SnakeMain snakeMain) {
 +      super();
 +      this.snakeMain = snakeMain;
 +      this.bitmap = snakeMain.bitmap;
 +
 +      // Wir starten mit dem Schlangenkopf in der Mitte des Zeichenbereichs:
 +      punkteX[0] = 15;
 +      punkteY[0] = 15;
 +      länge = 1;
 +      bitmap.setColor(15, 15, 0xff0000);
 +   }
 +
 +   public void act() {
 +      zeit++;
 +
 +      // Neue Kriechrichtung bestimmen:
 +      if(vx == 0) { 
 +         if(isKeyDown(Key.ArrowRight)) {
 +            vy = 0;
 +            vx = 1;
 +         }
 +         if(isKeyDown(Key.ArrowLeft)) {
 +            vy = 0;
 +            vx = -1;
 +         }
 +      } else {
 +         if(isKeyDown(Key.ArrowUp)) {
 +            vy = -1;
 +            vx = 0;
 +         }
 +         if(isKeyDown(Key.ArrowDown)) {
 +            vy = 1;
 +            vx = 0;
 +         }
 +      }
 +
 +      // wir gehen nur jedes 10-te Mal (ca. 1/3 s) einen Schritt weiter, ansonsten: return
 +      if(zeit % 8 != 0) return;
 +
 +      // Bisherige Koordinaten des Kopfes:
 +      int kopfX = punkteX[länge - 1];
 +      int kopfY = punkteY[länge - 1];
 +
 +      // An der alten Stelle des Kopfes wird ein Schlangenglied gezeichnet
 +      bitmap.setColor(kopfX, kopfY, 0x6060ff);
 +
 +      // Neue Kopfkoordinaten berechnen
 +      kopfX += vx;
 +      kopfY += vy;
 +
 +      if(kopfX < 0 || kopfY < 0 || kopfX > 29 || kopfY > 29 || 
 +            bitmap.getColor(kopfX, kopfY).toInt() == 0x6060ff) {
 +         // TODO: Game over
 +         println("Game Over!");
 +      } 
 +
 +      // Neue Kopfkoordinaten im Array speichern
 +      punkteX[länge] = kopfX;
 +      punkteY[länge] = kopfY;
 +      
 +      // Befindet sich an der neuen Kopfstelle eine Frucht?
 +      if(bitmap.getColor(kopfX, kopfY).toInt() != 0) {
 +         länge++;
 +         // TODO: Punkte vergeben!
 +      } else {
 +         // Schwanzende löschen und Koordinaten innerhalb der Arrays nachrücken
 +         bitmap.setColor(punkteX[0], punkteY[0], 0x0, 0);
 +         
 +         for(int i = 0; i < länge; i++) {
 +            punkteX[i] = punkteX[i + 1];
 +            punkteY[i] = punkteY[i + 1];
 +         }
 +      }
 +
 +      // Neue Kopfposition rot färben:
 +      bitmap.setColor(kopfX, kopfY, 0xff0000);
 +
 +   }
 +   
 +
 +}
 +
 +</script>
 +
 +</div>
 +
 +</HTML>