Lernpfad:Einführung in Processing/12

Aus Informatik-Box
Zur Navigation springen Zur Suche springen

Wir haben schon eine Menge der grundlegenden Programmierkonzepte erarbeitet. Nun wollen wir alles in einem kleinen Miniprojekt zusammenbringen: <colorize size="0">Raindrops</colorize> (Regentropfen).

Klicken, um das Programm zu starten.

Bei Raindrops fallen aus dem "Himmel" einzelne "Regentropfen" in Richtung "Erde". Auf der Erde versucht der Spieler die Tropfen mit seinem "Eimer" zu fangen. Für jeden Tropfen gibt es Punkte, bis zu viele Tropfen auf den Boden gefallen sind.

Icon Info.png

In deinem Projekt müssen keine Regentropfen in einen Eimer fallen. Es können auch Äpfel in einen Korb, Kühe in einen Stall oder Shuttles in das Dock der NCC-1701-D "fallen".

Icon Chalk board.png
Was du in diesem Schritt lernst
  • Ein komplexeres Projekt strukturiert entwickeln.
  • Bilder verwenden.
  • Kollisionen erkennen.


Ein Projekt dieser Art zu entwickeln erfordert einiges an Planung. Du solltest dir erst Teilprobleme überlegen, die du lösen musst und zum finalen Projekt zusammensetzen kannst. Implementiere jedes Teilproblem als eine eigene Methode.

Du kannst jederzeit im Lernpfad zurückgehen, um etwas nachzuschlagen.

Wenn du dich schon sicher fühlst im Umgang mit den bisherigen Programmierkonzepten, dann kannst das vorgeschlagene Miniprojekt gerne variieren. Nimm dir aber nicht zu viel vor! Besprich deine Ideen am besten vorher mit deiner Lehrperson.

Das Projekt strukturieren

Icon Heft.png
Arbeitsauftrag

Überlege dir zunächst genau, aus welchen Teilen das Programm besteht. Möchtest du einen Hintergrund zeichnen? Dann benötigst du eine Methode void zeichneHintergrund(). Sicherlich brauchst du eine Methode void zeichneRegentropfen( double x, double y ), die einen Regentropfen an die Position (x|y) zeichnet.

Notiere dir weitere Methoden, die implementiert werden müssen.


Bilder benutzen

Du kannst in Processing leicht Bilder einfügen und in deinen Programmen benutzen. Dazu benötigst du die Befehle loadImage(), um die Bilddatei zu laden und {{Processing Ref|image()}, um das Bild auf die Zeichenfläche zu zeichnen. Um ein Bild in einer Variablen zu speichern, wird der Datentyp PImage verwendet.

Für unser Spiel benötigen wir zwei Bilder: Einen Regentropfen und einen Eimer.

Lade die beiden Bilder runter (Rechtsklick -> Speicher unter..) und kopiere sie in deinen Projektordner (erstelle zunächst ein leeres Projekt und speichere es einmal ab). Probiere dann folgenden Code aus:

PImage tropfen;
PImage eimer;

void setup() {
  size(400, 600);
  
  eimer = loadImage("bucket_02.png");
  tropfen = loadImage("droplet.png");
}

void draw() {
  background(0,150,255);

  image(eimer, mouseX-25, 530, 50, 50);
  
  image(tropfen, random(50, 350), random(50, 300), 21.35, 30);
  image(tropfen, random(50, 350), random(50, 300), 21.35, 30);
  image(tropfen, random(50, 350), random(50, 450), 21.35, 30);
  
}

Kollisionen erkennen

Kollisionen zwischen Objekten in unserem Projekt (z.B. Regentropfen und Eimer) lassen sich erkennen, indem du die Koordinaten der Objekte vergleichst. Mit Koordinaten ist das Rechteck gemeint, dass das Objekt komplett einschließt.

Ist zum Beispiel ein Tropfen an den Koordinaten (x|y), dann sind die Eckpunkte des Tropfens durch (x|y), (x+width|y), (x+width|y+height) und (x|y+height) beschrieben.

Nun kannst du mit bedingten Anweisungen prüfen, ob sich dieses Rechteck mit dem eines anderen Objektes überschneidet:

if( tropfenX >= eimerX ) {
    if( tropfenX <= eimerX+eimerWidth ) {
        if( tropfenY >= eimerY ) {
            if( tropfenY <= eimerY+eimerHeight ) {
                // Die obere Linke Ecke des Toropfen (tropfenX|tropfenY)
                // liegt im Rechteck des Eimers!
            }
        }
    }
}
Icon Warning.png

tropfenX/tropfenY und eimerX/eimerY sind Variablen in denen die Koordinaten eines Tropfens und des Eimers gespeichert sind. Du kannst sie durch die entsprechenden Variablenbezeichner in deinem Projekt ersetzen.

Icon Info.png

Das Verschachteln von bedingten Anweisungen in dieser Art wird schnell unübersichtlich. Oft ist es besser, mehrere zusammenhängende Bedingungen zu verknüpfen. Dazu gibt es die logischen Operatoren, die du noch in 14 kennenlernst.

Das Beispiel oben kann man auch schreiben als:

if( tropfenX >= eimerX && tropfenX <= eimerX+eimerWidth
        && tropfenY >= eimerY && tropfenY <= eimerY+eimerHeight ) {
    // Kollision erkannt!
}

&& bedeutet hier "UND". Also muss die erste Bedingung erfüllt sein "UND" die Zweite. Du kennst diese Verknüpfung schon von digitalen Schaltungen!

Da du diese Prüfung immer wieder für alle Tropfen machen musst, bietet es sich an, dafür eine Methode mit Rückabe zu implementieren, die die x- und y-Koordinate eines Tropfen als Parameter übergeben bekommt und einen Wahrheitswert (boolean) zurückgibt, ob der Tropfen mit dem Eimer kollidiert:

boolean trifftEimer( float x, float y ) {
    if( x>= eimerX && x <= eimerX+eimerWidth
            && y >= eimerY && y <= eimerY+eimerHeight ) {
        return true;
    } else {
        return false;
    }
}
Icon Info.png

Denk daran, dass die x-Koordinate des Eimers durch mouseX festgelegt ist. Die y-Koordinate des Eimers ist fest.

Icon Info.png

Das Beispiel oben vergleicht immer die obere linke Ecke des Tropfens mit dem Rechteck des Eimers. Um einen anderen Punkt des Tropfens zu nutzen, musst du vor dem Vergleich die Koordinaten entsprechend anpassen (z.B. x = x + 10;).

Das Spiel neu starten

Tipps und Hinweise

Grundgerüst des Programms

Wenn du einen Startpunkt für das Projekt brauchst, dann übernimm diese Vorlage in Processing. Du musst nicht alle Methoden benutzen. Konzentriere dich zunächst auf das grundlegende Spielprinzip.

// Deklaration von Konfigurationsvariablen
// Siehe in startGame()
float speed;
int gefangen, gefallen;
int nextLevel;

// Bilder
PImage tropfen;
PImage eimer;

// Position Tropfen 1
float x1 = 0, y1 = 0;

void setup() {
    size(400, 600);

    // Bilder laden
    tropfen = loadImage("");
    eimer = loadImage("");

    tropfen.resize(21.35, 30);
    eimer.resize(50, 50);

    startGame();
}

void startGame() {
    // Startet das Spiel neu und initialisiert alle Variablen

    // Initialisierung der Startwerte
    speed = 4;      // Fallgeschw. der Tropfen
    gefangen = 0;   // Gefangene Tropfen
    gefallen = 0;   // Nicht gefangen
    nextLevel = 10; // Gefangene Tropfen für nächstes Level

    // Initialisierung der Tropfen
    x1 = 0;
    y1 = 0;
}

void draw() {
    // Zeichnet das Spielfeld neu
    background(0, 0, 248);
    // drawClouds();
    // draw Ground();

    image(tropfen, x1, y1);

    image(eimer, mouseX-25, 530);

    update();
    checkGame();
}

void update() {
    // Aktualisiere hier die Positionen der Tropfen und
    // ob die Tropfen den Eimer oder den Boden 
    // erreicht haben
}

void checkGame() {
    // Prüfe hier, ob das nächste Level erreicht wurde
    // oder ob das Spiel verloren wurde. 
}