Code of the Killertomaten

Vielleicht interessiert es ja manche hier, wie man in unter 100 Zeilen mit Processing ein solche kleines Spiel programmiert.  Deshalb folgt unten ohne große Erklärungen der Sourcecode. (Falls sich jemand wundert: Wegen eines Bugs im Syntax-Highlighting von wordpress.com für mehrzeilige Kommentare, s. https://github.com/alexgorbatchev/SyntaxHighlighter/issues/34, habe ich nur einzeilige Kommentare verwendet)

In Processing müsst ihr einen neuen „Sketch“ anlegen und die Bilddatei unter „Sketch -> Add File“ hinzufügen (was aber auch nichts weiter tut, als ein Unterverzeichnis data/ anzulegen, wohin die Datei kopiert wird). Den Code reinkopieren, starten – und wochenlanger Spielspaß ist euch gewiss! (Meine fünfjährige Tochter liebt das Spiel. „Mama, hast du schon gesehen, der Papa, der hat ein suuuper Tomatenspiel! Papa, darf ich nochmal?“)

Wenn ihr jetzt schreit „Ja, aber die Tomaten müssten eigentlich beim Abschießen platzen!“ oder „Find ich aber nicht so gut, dass man mehrere Tomaten auf einmal abschießen kann!“ oder „Aber das sollen doch Killertomaten sein – die sollten selbst auch irgendwie was Gefährliches machen!“ oder „Boah, man kann ja einfach auf der Leertaste bleiben – Dauerfeuer, was? Hihi! – Nee, ehrlich, ich finde das sollte nicht gehen!“ oder „Wäre doch voll witzig, wenn da auch Zucchini, Möhren und Blumenkohl rumfliegen würde – das wäre ja auch ein super Einstieg für Vererbung und Polymorphie, weil die dann ja eine andere Methode istUnterMauszeiger() haben müssten!“ – wenn ihr also irgendwas in der Art schreit, dann sage ich: Stimmt!

Genau solche Reaktionen habe ich von den Schülern auch bekommen (na ja, bis auf die letzte, das ist meine eigene!) Und ist das nicht toll? Die Schüler denken sofort und eigenständig über Erweiterungen des Arbeitsauftrags nach und der Lehrer braucht nur noch ihrem Drängen nachzugeben 😉

Und welche Ideen habt ihr?  (Ja, an IPad/Android-Umsetzung habe ich natürlich auch schon gedacht.)

// Angriff der Killertomaten!
// Version 2 - jetzt mit noch spektakulärerer Grafik

class Tomate {
  float xpos, ypos;  // Position der Tomate
  int durchmesser;   // Groesse
  float dirx, diry;  // Bewegungsrichtung

  // Konstruktor: Initialisiert die Tomate nach der Erzeugung
  Tomate(int x, int y, int d, float dx, float dy) {
    xpos = x;
    ypos = y;
    durchmesser = d;
    dirx = dx;
    diry = dy;
  }

  // prüft, ob Maus auf die Tomate zeigt
  boolean istUnterMauszeiger() {
    return dist(mouseX, mouseY, xpos, ypos) < durchmesser/2;
  }

  // berechnet die nächste Position der Tomate und ändert evtl ihre Richtung
  void move() {
    if ((xpos-durchmesser/2< 0) || (xpos+durchmesser/2 > width)) {
      dirx = dirx * -1;
    }
    if ((ypos-durchmesser/2 < 0) || (ypos-durchmesser/2+durchmesser > height)) {
      diry = diry * -1;
    }
    xpos = xpos + dirx;
    ypos = ypos + diry;
  }

  // zeichnet die Tomate an ihrer momentanen Position
  void display() {
    image(bild, xpos-durchmesser/2, ypos-durchmesser/2, durchmesser, durchmesser);
    if (istUnterMauszeiger()) {
      // hebe diejenige Tomaten hervor, auf die gerade "gezielt" wird
      ellipse(xpos, ypos, durchmesser, durchmesser);
    }
  }
}

// Globale Variablen (s. Blog)
int NUM_TOMATEN = 50;   // Gesamtzahl Tomaten
float SPEED = 1.7;      // Geschwindigekeitsfaktor, der benutzt werden kann, um die Schwierigkeit zu steigern/senken
int score = 0;          // Punktestand
ArrayList tomaten = new ArrayList();   // Liste aller noch nicht abgeschossenen Tomaten
float startTime = -1;   // Zeit wird gemessen, sobald die erste Tomate angeklickt wurde
PImage bild;            // speichert die Tomaten-Grafik

// wird automatisch bei Start aufgerufen; bereitet alles für den weiteren Programmablauf vor
void setup() {
  size(700, 500);
  smooth();
  noFill();
  stroke(0);
  bild = loadImage("tomate.png");
  int maxRadius = 35;
  for (int i=0; i < NUM_TOMATEN; i++) {
    int x = (int) random(maxRadius, width-maxRadius);
    int y = (int) random(maxRadius, height-maxRadius);
    int d = (int) random(maxRadius, maxRadius*2);
    float dx = random(-1, 1) * SPEED;
    float dy = random(-1, 1) * SPEED;
    Tomate t = new Tomate(x, y, d, dx, dy);
    tomaten.add(t);
  }
}

// Dies ist die zentrale Komponente des Programms, der "game loop" (http://en.wikipedia.org/wiki/Game_programming#Game_structure).
// draw() wird von Processing automatisch ca. 60mal/Sekunde aufgerufen.
void draw() {
  background(255);
  for (int i=0; i < tomaten.size(); i++) {
    Tomate t1 = (Tomate) tomaten.get(i);
    t1.move();
    t1.display();
    if ((keyPressed) && (key == ' ') && t1.istUnterMauszeiger()) {
      tomaten.remove(i);
      if (startTime == -1) {
        startTime = millis();   // starte Zeitmessung bei der ersten abgeschossenen Tomate
      }
      score = 10000 * (NUM_TOMATEN-tomaten.size()) - (int) (millis()-startTime);
    println("Punktestand: " + score);
    }
  }
  if (tomaten.size() == 0) {
    println();
    println("Gratulation! Du hast den Angriff der Killertomaten abgewehrt!");
    println("Gesamtpunktzahl: " + score);
    exit();
  }
}

Ganz noch kurz zu den „globalen Variablen“: In Wirklichkeit gibt’s sowas in Java natürlich nicht. Das ganze Processing-Programm wird intern in eine Subklasse der Klasse PApplet umgewandelt. D.h. die „globalen“ Variablen sind in Wirklichkeit Attribute dieser Klasse. Man sieht das schön, wenn man den Schritt vom Processing-Editor zu Eclipse macht (http://processing.org/learning/eclipse/). Ich könnte mir vorstellen, dass das ein sinnvoller Dreischritt zur Einführung von Java ist:

  1. Processing mit dem internen Editor: Spielerisch Java kennenlernen ohne das ganze nervige Java-Drumrum
  2. Processing + Eclipse: Erstmal keine neuen Progammierkonzepte, sondern dient v.a. der Einführung in Eclipse
  3. Eclipse mit anderen Java-Projekten: „…und morgen die ganze Welt!“

Je nachdem, was ich im nächsten Schuljahr an Klassen bekomme, kann ich das ja mal ausprobieren.

Tomate


Das harmlose Äußere trügt!

Advertisements

2 Gedanken zu „Code of the Killertomaten

  1. Ja, mich interessiert es, wie man so ein Spiel programmiert. Ich wollte schon beim letzten Mal kommentieren, fand aber keine Zeit. Ich hoffe sehr, dieses Jahr auch noch zu etwas Processing zu kommen.

    • Freut mich sehr! Das ist natürlich wahrlich nicht der Weisheit letzter Schluss; man könnte es auch noch schöner und übersichtlicher programmieren, aber es steckt schon viel Interessantes drin, finde ich, und das Erweiterungspotential ist groß. Vereinfachen kann man, je nach Bedarf, auch: Ich hätte z.B., weil Container wie ArrayList noch nicht eingeführt waren, das Spiel erstmal mit drei „von Hand“ erzeugten Tomaten und ohnen die Schleife in draw() fertig programmieren lassen. Den Punktestand macht man sicher auch erst von der Zeit abhängig, wenn sich die ersten beschweren, dass alle immer gleichviele Punkte bekommen. Usw, usw, usw.

      Übrigens: Ich hab ja gesehen, dass ihr in Bayern ausgiebig Zustandsautomaten thematisiert. Wenn man will, dass Tomaten nach Abschuss platzen o.ä. dann kommt man in Processing an einem Zustandsautomaten (oder einer Billigversion davon mit zumindest booleschen Variablen à la „if istNichtMehrAmLeben then …“) kaum herum.

      P.S. Ich habe gerade nochmal eine Kleinigkeit geändert (in Zeile 61 wurde vorher noch nicht die Konstante NUM_TOMATEN verwendet).

      P.P.S. Schluss mit Informatik für heute. Jetzt wird Ukulele gespielt und heute abend das Downton Abbey Christmas Special geschaut! Wetter passt halbwegs!

Kommentar verfassen

Trage deine Daten unten ein oder klicke ein Icon um dich einzuloggen:

WordPress.com-Logo

Du kommentierst mit Deinem WordPress.com-Konto. Abmelden / Ändern )

Twitter-Bild

Du kommentierst mit Deinem Twitter-Konto. Abmelden / Ändern )

Facebook-Foto

Du kommentierst mit Deinem Facebook-Konto. Abmelden / Ändern )

Google+ Foto

Du kommentierst mit Deinem Google+-Konto. Abmelden / Ändern )

Verbinde mit %s