- 30.09.2024: Challenge hinzugefügt
- 09.01.2024: Level zu Aufgaben hinzugefügt
- 15.01.2023: Motivation oben und Aufgabenverlinkung
- 27.12.2021: Neue Aufgabe "Goldener Schnitt" in 3.1
- 21.11.2021: Neue Aufgabe "Endless Landscape" in 3.1, neuer Website-Link und drei neue Abb. bei 3.6 Kollision
- 06.11.2021: Neue Aufgabe in 3.6 "Drag and drop"
- 02.11.2021: Kleinere Korrekturen...
- 03.10.2021: Lernziele angepasst
- 02.08.2021: Neue Kapitelnummerierung
Lernziele
- Sie können den Begriff Kontrollfluss erklären
- Sie kennen den Aufbau einer If-Anweisung und den Begriff Code-Block
- Sie können eine Bedingung für eine If-Anweisung anhand einer Problemstellung formulieren
- Sie können den Kontrollfluss von If und If-Else mit Hilfe von Flussdiagrammen erklären
- Sie können Fallunterscheidungen mit If und If-Else programmieren, sowohl für statische Probleme als auch für Animationen
- Sie können den Kontrollfluss If-Else-If mit einem Flussdiagrammen erklären
- Sie können Fallunterscheidungen mit If-Else-If programmieren
- Sie können boolesche Ausdrücke mit AND/OR für konkrete Anwendungsfälle formulieren
- Sie wissen, wie man boolesche Variablen in konkreten Anwendungsfällen nutzt
- Sie können mit Hilfe von If-Anweisungen auf bestimmte Tasten reagieren, auch bei kontinuierlichen Szenarien
- Sie können Kollisionen zwischen einem Punkt (z.B. Mausposition) mit einem Rechteck oder einem Kreis bestimmen
Voraussetzungen
Sie sollten sicher mit Variablen umgehen können Kapitel 2.
Challenge
Was wollen Sie nach dem Durcharbeiten des Kapitels programmieren können? Zwei Vorschläge:
Im linken Fenster sehen Sie, wie man mit Hilfe einer If-Anweisung den Ball abhängig von seiner Position einfärben kann. Das rechte Fenster müssen Sie erst anklicken, dann können Sie das Raincatcher-Spiel mit den Richtungstasten spielen.
Schaffen Sie es, diese Programme zu schreiben?
Sie finden die beiden Aufgaben auch unter 3.3 (e) und 3.6 (c). Vorübungen zu dem Raincatcher-Spiel sind 3.5 (a) und (b).
Normalerweise wird Ihr Code Zeile für Zeile, von oben nach unten, ausgeführt. Manchmal möchte man aber eine Zeile - oder einen ganzen Block von Zeilen - aber nur unter einer bestimmten Bedingung durchführen. Sie möchten das Raumschiff nur dann nach links bewegen, wenn eine bestimmte Taste gedrückt ist. Sie möchten eine Erfolgsmeldung nur dann ausgeben, wenn eine bestimmte Punktzahl erreicht wurde. Dafür gibt es die If-Anweisung. Sie erlaubt es, im Code zu "springen" und somit den sogenannten Kontrollfluss zu verändern.
3.1 Einfache If-Anweisung
Video: Einführung in die If-Anweisung (9:49)
Nehmen wir an, Ihr Programm soll einem Prüfling sagen,
ob er bestanden hat. Das sei dann der Fall, wenn die
Punktzahl (Variable
punkte
) mindestens
50 beträgt. Im Code wird das so gelöst:
int punkte = 75; if (punkte >= 50) { println("bestanden"); }
Die Zeile mit der Print-Anweisung wird nur unter der Bedingung
ausgeführt, dass der Wert von punkte
größer oder gleich
50 ist. Ansonsten wird die Zeile übersprungen. Wir ändern also
den normalen Kontrollfluss.
Flussdiagramm
Das können wir auch als Flussdiagramm visualisieren (man nennt das auch Programmablaufplan):
Im Flussdiagramm stellen Kästen normale Befehle/Anweisungen dar, die
Pfeile zeigen, welche Anweisung als nächstes ausgeführt wird.
Eine Raute symbolisiert eine Entscheidung: Von hier aus
gehen zwei Pfeile aus, einer mit true
, einer mit false
beschriftet. Man wählt den Pfeil, der der Bedingung entspricht (die
entweder zu true oder false evaluiert worden sein muss).
Man sieht in dem Diagramm sehr schön, dass der Kasten mit "bestanden" nicht immer ausgeführt wird, da sich der Kontrollfluss an der Raute aufteilt.
Wir erweitern unseren Code um eine Zeile hinter der If-Anweisung:
int punkte = 75; if (punkte >= 50) { println("bestanden"); } println("tschüs");
Wir erweitern unser Flussdiagramm entsprechend, um zu klären, wann diese neue Codezeile ausgeführt wird.
Wir sehen, dass "tschüs" immer ausgegeben wird, unabhängig davon, ob die Bedingung erfüllt ist oder nicht. Wir sind wieder im "regulären" Kontrollfluss.
Bedingung
Die allgemeine Form der If-Anweisung ist:
if (BEDINGUNG) ANWEISUNG
Eine Anweisung ist entweder eine einzelne Code-Zeile (Befehl, Variablenzuweisung ...) oder - wie in unseren Beispielen - ein Code-Block, der mit geschweiften Klammern markiert ist. Auf Code-Blocks gehen wir im nächsten Abschnitt ein.
Eine Bedingung ist ein sogenannter boolescher Ausdruck, benannt
nach dem britischen Mathematiker George Boole.
Ein boolescher Ausdruck ist ein Ausdruck, der nach Auswertung immer entweder wahr (true) oder
falsch (false) ist. Die zwei einfachsten booeschen Ausdrücke sind true
und false
.
Sie können z.B. schreiben:
if (true) { println("immer"); }
Die obige Anweisung wird immer ausgeführt, was natürlich wenig sinnvoll ist (man kann das if dann auch einfach weglassen), aber es zeigt, dass das Schlüsselwort true
(genauso wie false
) eine vollwertige Bedingung sein kann.
Eine weiterer boolescher Ausdruck ist ein numerischer Vergleich. Beispiele:
10 > 100 x > 5 + y 41 == foo x != y 33 < boo
Auf beiden Seiten des Vergleichs
- können beliebig komplexe arithmetische Ausdrücke stehen.
- können Variablen vorkommen, diese werden bei der Abarbeitung durch ihre aktuellen Werte ersetzt.
Beachten Sie insbesondere das "gleich". Es muss mit doppeltem Gleichheitszeichen geschrieben werden! Es ist ein häufiger Anfängerfehler hier nur ein einfaches Gleichheitszeichen zu setzen, da in diesem Fall keine Fehlermeldung ausgegeben wird! Es wird dann nämlich eine Zuweisung vorgenommen, d.h. die Variable, die Sie nur "testen" wollen, wird verändert!
x == 5 z == k 42 == foo
Im Vergleich zu den Vergleichsoperatoren, die man aus der Schule kennt, ist zu beachten:
-
Für "kleiner gleich" schreiben Sie
<=
und zwar in genau dieser Reihenfolge. Ähnlich für "größer gleich". - Für "gleich" schreiben Sie ein doppeltes Gleichheitszeichen.
-
Für "ungleich" wird
!=
geschrieben. Das Ausrufezeichen ist nämlich für Negation zuständig.
Code-Block
Die geschweiften Klammern in den obigen Beispielen markieren jeweils einen sogenannten Code-Block. Code-Blocks erlauben uns, viele Zeilen "zusammenzupacken" und bei der If-Anweisung als Aktion zu definieren, die ausgeführt wird, wenn die Bedingung wahr ist.
Code-Blocks werden uns noch in vielen anderen Zusammenhängen begegnen, z.B. bei Funktionen, Schleifen und Klassen. Beachten Sie, dass die Zeilen innerhalb des Code-Blocks eingerückt sind und zwar alle gleich, so dass man direkt sieht, dass diese Zeilen zusammengehören. In der Processing-Umgebung können Sie das automatisch durchführen lassen im Menupunkt Edit > Auto Format oder mit der Tastenkombination CMD+T (Mac) bzw. STRG+T (Windows).
Die Einrückung ist wichtig, weil ein Code-Block weitere Code-Blöcke enthalten kann. Das heißt die Blöcke können verschachtelt sein. Hier ein Beispiel:
int punkteTest = 75; int zusatzTest = 85; if (punkteTest >= 50) { println("Test ist bestanden!"); if (zusatzTest >= 50) { println("Zusatztest ist AUCH bestanden!"); } }
Der Else-Teil
Wollen wir auch eine Aktion immer dann ausführen, wenn die Bedingung nicht erfüllt ist, können wir noch einen Else-Teil (else heißt "sonst") anfügen:
int punkte = 75; if (punkte >= 50) { println("bestanden"); } else { println("durchgefallen"); } println("tschüs");
Auch hier können wir den Kontrollfluss mit einem Flussdiagramm verdeutlichen:
Eine wichtige Erkenntnis ist, dass, egal ob die Bedingung true oder false ist, immer Code ausgeführt wird (im Diagramm entweder der rechte Ast oder der linke Ast).
Die If-Else-Anweisung ist als ein einziges, zusammengehöriges Konstrukt zu betrachten, der zwei Code-Blöcke enthält. Nach dem If-Else geht es regulär Zeile für Zeile weiter, hier folgt also auch immer das "tschüs".
Beispiel: Fliegender Ball
Nehmen wir an, Sie animieren einen Ball, von links nach rechts zu fliegen. Wenn er rechts aus dem Bildschirm tritt, soll er links wieder auftauchen:
Das Basisprogramm sieht zunächst mal so aus:
int x = 0; void setup() { size(200, 100); } void draw() { background(0); ellipse(x, height/2, 20, 20); x++; }
In dieser Version fliegt der Ball genau einmal über den Bildschirm und verschwindet dann auf Nimmerwiedersehen.
Überlegen Sie, was folgender Satz bedeutet:
Wenn er rechts aus dem Bildschirm tritt, soll er links wieder auftauchen.
Der erste Teilsatz ist eine Bedingung, das sieht man an dem "Wenn". Wie übersetzen Sie diese Bedingung in Code? Sie betrachten sich Ihre Variablen - das ist in diesem Fall x - und überlegen, wann die Bedingung
Wenn er rechts aus dem Bildschirm tritt
erfüllt ist. Die Antwort: wenn das x genau so groß wird wie das Fenster breit ist, bei unserem 200x100-Fenster also:
x == 200
Denken Sie immer daran, bei Vergleichen das doppelte Gleichheitszeichen zu verwenden.
Noch besser ist es, diese Bedingung allgemein zu halten, denn es könnte sein, dass Sie das Grafikfenster größer oder kleiner stellen. Verwenden Sie die Systemvariable width
, die die aktuelle Breite des Grafikfensters
enthält.
x == width
Kommen wir zum zweiten Teilsatz:
..., soll er links wieder auftauchen.
Was bedeutet es, dass der Ball links auftaucht? Ganz einfach: dass der x-Wert
wieder auf Null gesetzt wird. Wir testen also in unserem Programm in jedem Durchlauf von draw(),
ob das x == width
ist und, wenn das der Fall ist, setzen wir x auf Null:
int x = 0; void draw() { background(0); ellipse(x, height/2, 20, 20); x++; if (x == width) { x = 0; } }
Geschwindigkeit
Die Bewegung des Balls wird durch das x++
verursacht.
Bei jedem Durchlauf von draw() wird das x um genau 1 erhöht.
Wenn wir das x jedesmal um 3 erhöhen würden, wäre der Ball schneller.
Um hier flexibel zu sein, führen wir eine neue Variable
als Geschwindigkeit mit Namen speed
ein.
Statt einer konstanten Zahl wie 1 wird der Wert dieser Variable auf das x addiert. Wir nehmen hier mal Geschwindigkeit 3:
int x = 0; int speed = 3; void draw() { background(0); ellipse(x, 50, 20, 20); x = x + speed; // VORSICHT! if (x == width) { x = 0; } }
Plötztlich funktioniert das Neu-Erscheinen des Balls nicht mehr, er verschwindet einfach! Warum? Schauen wir uns mal an, welche Werte das x annimmt, indem wir uns x auf der Konsole ausgeben:
0 3 6 12 ... 93 96 99 102 105
Das Problem ist, dass x nicht genau 100 wird, sondern darüber hinweg springt. Deshalb müssen wir unsere If-Bedingung allgemeiner fassen. Man sagt auch, dass man die Bedingung relaxiert, also etwas "weicher" fasst.
if (x >= width) { x = 0; }
Das komplette Programm (ob man hier > oder >= verwendet, spielt keine Rolle):
int x = 0; int speed = 3; void draw() { background(0); ellipse(x, 50, 20, 20); x = x + speed; if (x > width) { x = 0; } }
Rückwärts fliegen
Wenn Sie die Geschwindigkeit mit einer negativen Zahl belegen, können Sie den Ball auch rückwärts fliegen lassen:
int x = 100; int speed = -2; void draw() { background(0); ellipse(x, 50, 20, 20); x = x + speed; if (x < 0) { x = width; } }
Ihnen ist hoffentlich aufgefallen, dass die If-Anweisung verändert wurde. Auf deutsch lautet die Anweisung jetzt:
Wenn der Ball links aus dem Bildschirm tritt, soll er rechts wieder auftauchen.
"Links aus dem Bildschirm treten" übersetzt sich zur Bedingung x < 0
und
"rechts wiederauftauchen" realisiert man mit der Anweisung x = width
.
Coding Style
Bitte achten Sie darauf, wo Leerzeichen und Zeilenumbrüche gemacht werden, und wo nicht.
if (x > 100) { x = 0; }
Alternativ kann man einen Umbruch nach der Bedingung einfügen:
if (x > 100) { x = 0; }
Denken Sie auch daran, Ihre Code mit Bearbeiten > Autoformatierung von Processing korrekt einrücken zu lassen (Tastenkürzel STRG+T bzw. CMD+T).
Fingerübungen
a) Größer 50
Gegeben sei eine int-Variable foo. Wenn diese größer als 50 ist, soll "OK" ausgegeben werden. Nehmen Sie verschiedene Werte für foo, um Ihr Programm zu testen.
int foo = 60; if (foo > 50) { println("OK"); }
b) a gewinnt
Gegeben seien zwei int-Variablen a und b. Wenn a um mindestens 10 größer ist als b, soll "a gewinnt" ausgegeben werden. Nehmen Sie verschiedene Werte für a und b, um Ihr Programm zu testen.
int a = 50; int b = 20; if (a - 10 >= b) { println("a gewinnt"); }
c) Summe gewinnt
Gegeben seien vier float-Variablen a, b, c, d. Wenn die Summe von a und b größer ist als die Summe von c und d, dann soll "Team ab gewinnt" ausgegeben werden.
int a = 5; int b = 2; int c = 5; int d = 0; if (a + b > c + d) { println("Team ab gewinnt"); }
d) If-Else
Gegeben seien zwei int-Variablen z1 und z2. Wenn die zwei Zahlen gleich sind, soll "gleich" ausgegeben werden, sonst "ungleich".
Lösen Sie die obige Aufgabe, indem Sie im ersten If-Teil "ungleich" ausgeben und im Else-Teil "gleich". Passen Sie dazu die Bedingung an.
int z1 = 5; int z2 = 11; if (z1 == z2) { println("gleich"); } else { println("ungleich"); }Für die zweite Variante:
if (z1 != z2) { println("ungleich"); } else { println("gleich"); }
Übungsaufgaben
3.1 a) Gerade/ungerade Level 21 = easy
2 = relativ leicht
3 = mittel
4 = schwierig
5 = hart
Gegeben sei die int-Variable zahl. Wenn die Zahl gerade ist, soll "gerade" ausgegeben werden, sonst "ungerade".
3.1 b) Verschachteltes If Level 11 = easy
2 = relativ leicht
3 = mittel
4 = schwierig
5 = hart
Gegeben seien drei int-Variablen a, b und x.
Wenn x zwischen den Zahlen a und b liegt, sollen Sie "drin" auf der Konsole ausgeben.
Gehen Sie davon aus, dass a kleiner als b ist!
Schreiben Sie zunächst eine If-Anweisung und dann eine zweite innerhalb der ersten.
Hinweis: Verwenden Sie hier kein UND.3.1 c) Klausurnoten Level 31 = easy
2 = relativ leicht
3 = mittel
4 = schwierig
5 = hart
Sie haben eine Punktzahl gegeben:
int punkte = 10;
Schreiben Sie ein Programm, dass bei einer Punktzahl von mindestens 5 ausgibt:
Bestanden! Auf Wiedersehen.
Bei 4 oder weniger Punkten, wird ausgegeben:
Leider durchgefallen :( Auf Wiedersehen.
Hinweis: Verwenden Sie if-else und vermeiden Sie, dass Code-Zeilen mit der gleichen Anweisung zwei Mal auftreten.
Im nächsten Schritt erweitern Sie Ihr Programm, so dass bei verschiedenen Punktständen jeweils folgendes ausgegeben wird:
0 - 4: Durchgefallen 5 - 9: Bestanden 10 - 15: Bestanden mit Auszeichnung
Testen Sie Ihr Programm mit den Werten 0, 15 und 25.
3.1 d) Stehenbleiben Level 21 = easy
2 = relativ leicht
3 = mittel
4 = schwierig
5 = hart
Ändern Sie das folgende Programm derart, dass der Ball stehenbleibt, sobald er die Mitte erreicht. Das heißt, der Ball bewegt sich bis zur Mitte und bleibt dann dort.
int x = 0; void draw() { background(255); ellipse(x, 50, 20, 20); x++; if (x > width) { x = 0; } }
3.1 e) Hoch-runter Level 11 = easy
2 = relativ leicht
3 = mittel
4 = schwierig
5 = hart
Ändern Sie das obige Programm derart, dass der Ball von oben nach unten fliegt.
3.1 f) Wachsen pro Durchlauf Level 11 = easy
2 = relativ leicht
3 = mittel
4 = schwierig
5 = hart
Der Ball fliegt wiederholt von links nach rechts. Bei jedem Durchlauf soll der Ball etwas größer sein.
3.1 g) Wiederholtes Wachsen Level 11 = easy
2 = relativ leicht
3 = mittel
4 = schwierig
5 = hart
Ein mittig platzierter Kreis wird stetig größer, bis er den Rand des Fensters erreicht, dann beginnt er wieder als ein kleiner Kreis zu wachsen.
3.1 h) Mutierender Mauszeiger Level 11 = easy
2 = relativ leicht
3 = mittel
4 = schwierig
5 = hart
Folgendes Programm erzeugt einen Mauszeiger in Form eines Kreises. Verändern Sie das Programm derart, dass in der rechten Bildschirmhälfte der Mauszeiger zur gefüllten, schwarzen Box wird (mittig zum Mauszeiger) und in der linken wieder zum leeren Kreis.
void draw() { background(255); ellipse(mouseX, mouseY, 20, 20); }
3.1 i) Timer Level 31 = easy
2 = relativ leicht
3 = mittel
4 = schwierig
5 = hart
Sie möchten ein Programm schreiben, dass jede Sekunde einen Punkt auf die Konsole schreibt (verwenden Sie print
statt println
), d.h. nach 10 Sekunden sehen Sie:
..........
Schreiben Sie zunächst ein Programm, das alle 60 "Zyklen" einen Punkt schreibt. Ein Zyklus bedeutet, dass ein Mal draw()
aufgerufen wurde. Verwenden Sie eine Zählervariable:
int count = 0;
Hinweis 1:
Je nach Rechner und aktueller Rechnerbelastung wird draw()
auch seltener als 60 Mal aufgerufen. Die Systemvariable frameRate
(float) gibt an, wie oft draw()
aktuell pro Sekunde aufgerufen wird. Nutzen Sie dies, um ziemlich genau 1x pro Sekunde einen Punkt zu malen.
Hinweis 2: Nutzen Sie nicht die Funktion frameRate(), sondern die Systemvariable frameRate wie oben angegeben.
3.1 j) Glücksspiel Level 21 = easy
2 = relativ leicht
3 = mittel
4 = schwierig
5 = hart
Sie möchten ein Glücksspiel realisieren, wo bei jedem Tastendruck mit einer bestimmten Wahrscheinlichkeit (in Prozent) ein "gewonnen" ausgegeben wird (sonst "verloren").
Ihr Programm könnte so aussehen:
int gewinnChance = 20; void draw() {} void keyPressed() { // Ihr Code }
Testen Sie Ihr Programm, indem Sie 10x eine Taste drücken und schauen, ob der Anteil der gewonnenen Runden ungefähr Ihrer Angabe in gewinnChance
entspricht.
random()
, um eine Zahl zwischen 0 und 100 zu generieren. Das ist sozusagen Ihr "Würfel".
3.1 k) Endless Landscape Level 41 = easy
2 = relativ leicht
3 = mittel
4 = schwierig
5 = hart
Animieren Sie ein "Gebirge", das von rechts nach links zieht.
Wenn Sie das obige Gebirge geschafft haben, fügen Sie einfach noch einen Punkt hinzu.
3.1 l) Stoppuhr Level 21 = easy
2 = relativ leicht
3 = mittel
4 = schwierig
5 = hart
Programmieren Sie eine Art Stoppuhr-Anzeige, die immer wieder von vorn beginnt.
arc()
, die ein Kreissegment zeichnet.
Denken Sie daran, dass der erste Winkel kleiner als der zweite sein muss.
Sie können auch negative Winkel verwenden.
3.1 m) Goldener Schnitt Level 51 = easy
2 = relativ leicht
3 = mittel
4 = schwierig
5 = hart
Wir betrachten eine Strecke c und zerlegen sie in die zwei Teilstrecken a und b. Wir nehmen mal an, dass a die längere der beiden Teilstrecken ist und b die kürzere.
Jetzt kann man sich bestimmte Längenverhältnisse anschauen. Das eine Verhältnis ist a:b, also das Verhältnis der zwei Teilstrecken zueinander, genauer gesagt, das Verhältnis der langen Teilstrecke a zur kurzen Teilstrecke b. Das andere Verhältnis ist c:a, also das Verhältnis der gesamten Strecke c zu der längeren Teilstrecke a. Diese Verhältnisse berechnet man einfach per Division - etwa c/a - und erhält so eine Dezimalzahl. Ist die Strecke c eineinhalb Mal so lang wie a, dann ist das Verhältnis c:a also 1.5.
Der Goldene Schnitt bezieht sich auf eine ganz bestimmte Teilung, nämlich diejenige Teilung, die erreicht, dass beide Verhältnisse genau gleich sind, also c:a = a:b. In dem verlinkten Wikipedia-Artikel finden Sie den genauen Wert.
Programmieren Sie eine Visualisierung des Goldenen Schnitts, bei der man die Strecke c sieht, sowie die Teilstrecken a und b. Mit der x-Position der Maus kontrolliert man die Teilung von c. Aufgabe ist es, die Länge von a so zu bestimmen, dass sich der Goldene Schnitt ergibt. Ob der Goldene Schnitt erreicht ist, prüfen Sie, indem Sie die Verhältnisse c:a und a:b vergleichen. Probieren Sie es unten aus und programmieren Sie es entsprechend.
Um zu bestimmen, ob zwei Float-Zahlen "gleich" sind, betrachten Sie den Betrag der Differenz zweier Float-Werte. Den Betrag bekommen Sie mit der Funktion abs
. Das Programm soll bis zur zweiten Nachkommastelle genau sein.
Zusammenfassung
Eine If-Anweisung erlaubt es, eine oder mehrere Code-Zeilen (einen Code-Block) nur unter einer ganz bestimmten Bedingung auszuführen.
-
Eine Bedingung wird durch einen booleschen Ausdruck definiert. Dies ist ein Ausdruck, der zu true oder false
ausgewertet werden kann. Die Schlüsselworte
true
undfalse
sind jeweils (triviale) boolesche Ausdrücke. Wichtiger sind arithmetische Vergleiche wiex > 5
oder10 == y
. WICHTIG: Immer doppeltes Gleichheitszeichen beim Vergleich nehmen! - Ein Code-Block ist eine Anzahl von Anweisungen (können also mehrere Zeilen sein), von von geschweiften Klammern umgrenzt sind. Die Code-Zeilen innerhalb der Klammern sind in Processing alle gleich weit eingerückt, so dass man leicht erkennt, in welchem Block sich eine Zeile befindet.
- Möchte man Code-Zeilen genau dann ausführen, wenn die Bedingung nicht erfüllt ist, so hängt man mit Hilfe von else einen zweiten Code-Block an, der genau dann ausgeführt wird.
3.2 If-Else-If
Video: Else if (9:24)
Wenn Sie größere Fallunterscheidungen haben, bietet sich das If-Else-If an.
Möchten Sie zum Beispiel verschiedene Aktionen abfeuern, je nachdem ob ein Prüfling mehr als 75, mehr als 50 oder weniger als 50 hat, müssten Sie zwei If-Anweisungen verschachteln:
int punkte = 55; // äußere If-Anweisung if (punkte > 50) { // innere If-Anweisung if (punkte > 75) { println("Bestnote!"); } else { println("Bestanden."); } } else { println("Leider durchgefallen"); // Else-Teil }
Die äußere If-Anweisung unterscheidet zwischen >50 und <=50. Die innere If-Anweisung teilt den Bereich >50 dann nochmal in >75 und <=75.
Auch wenn Verschachtelung erlaubt und in manchen Fällen auch sinnvoll ist, so ist dieser Code doch schwer zu lesen und je mehr Fälle Sie haben, umso unübersichtlicher wird der Code.
Das Else-If erlaubt Ihnen, eine zweite Bedingung hinzuzufügen. Diese Bedingung wird nur dann geprüft, wenn die erste falsch ist. Das schlussendliche Else greift dann, wenn beide Bedingungen falsch waren.
int punkte = 55; if (punkte > 75) { println("Bestnote!"); } else if (punkte > 50) { println("Bestanden."); } else { println("Leider durchgefallen"); // Else-Teil }
Es können beliebig viele Else-If-Teile eingefügt werden:
int punkte = 55; if (punkte > 90) { println("Bestnote!"); } else if (punkte > 75) { println("Sehr gut."); } else if (punkte > 50) { println("Bestanden."); } else { println("Leider durchgefallen"); // Else-Teil } println("tschüs");
Processing testet zuerst die erste Bedingung. Falls diese falsch ist, wird das erste Else-If getestet. Falls dies falsch ist, wird das nächste Else-If getestet und so fort. Sind alle diese Bedingungen falsch, so wird der Else-Teil ausgeführt. Danach wird zum normalen Kontrollfluss zurückgekehrt.
Allgemein kann man das so schreiben:
if (BEDINGUNG-1) ANWEISUNG-1 else if (BEDINGUNG-2) ANWEISUNG-2 else if (BEDINGUNG-3) ANWEISUNG-3 ... else ANWEISUNG-N
Flussdiagramm
Als Flussdiagramm sieht das so aus:
Man sieht hier deutlich, dass nur genau eine Option (d.h. ein Code-Block) ausgeführt wird. Danach wird zum normalen Kontrollfluss zurückgekehrt.
Coding Style
Bitte achten Sie darauf, wo Leerzeichen und Zeilenumbrüche gemacht werden, und wo nicht.
if (foo > 200) { println("foo"); } else if (foo > 100) { println("bar"); } else { println("sonst"); }
Alternativ:
if (foo > 200) { println("foo"); } else if (foo > 100) { println("bar"); } else { println("sonst"); }
Denken Sie auch daran, Ihre Code mit Bearbeiten > Autoformatierung von Processing korrekt einrücken zu lassen (Tastenkürzel STRG+T bzw. CMD+T).
Fingerübungen
a) Positiv/negativ
Gegeben sei eine int-Variable zahl. Wenn diese größer als oder gleich 0 ist, soll "positv" ausgegeben werden. Wenn sie kleiner als 0 ist, soll "negativ" ausgegeben werden. Probieren Sie verschiedene Werte für zahl, um Ihr Programm zu testen.
int zahl = -5; if (zahl >= 0) { println("positiv"); } else { println("negativ"); }
Übungsaufgaben
3.2 a) Klausurnoten Level 11 = easy
2 = relativ leicht
3 = mittel
4 = schwierig
5 = hart
Lösen Sie eine ähnliche Aufgabe wie die im letzten Abschnitt mit if-else-if
. Sie haben eine Punktzahl gegeben:
int punkte = 10;
Schreiben Sie Code, so dass bei verschiedenen Punktständen ausgegeben wird, wie die Klausur ausfällt:
0 - 10: Durchgefallen 11 - 20: Naja 21 - 30: Mittelgut 31 - 40: Gut 41 - 50: Super
Testen Sie Ihr Programm mit den Werten 0, 15, 25, 35, 45.
3.2 b) Lauftext Level 21 = easy
2 = relativ leicht
3 = mittel
4 = schwierig
5 = hart
Sie schreiben eine Textanzeige, die bei Mausklick zum nächsten Wort wechselt. Das erste Wort ist "Hallo":
int zustand = 0; void setup() { textAlign(CENTER); textSize(20); } void draw() { background(0); if (zustand == 0) { text("Hallo", width/2, height/2); } }
Ergänzen Sie den Code, dass bei jedem Mausklick ein neues Wort angezeigt wird. Nach "Hallo" kommt "mein", "Name", "ist", "Hase", "Tschüs". Danach geht es wieder von vorn los.
(Interaktives Feld:)
Nutzen Sie die Variable zustand
und eine if-else-if Konstruktion.
3.3 Boolesche Ausdrücke
Video: Boolesche Ausdrücke mit AND und OR (8:38)
Um komplexere Sachverhalte auszudrücken, müssen Sie evtl. mehrere Vergleiche kombinieren. Solche Kombinationen sind wieder boolesche Ausdrücke und können also als Bedingung für das If verwendet werden.
Die genannten Kombinationen werden über sogenannte logische Operatoren hergestellt.
Logisches UND
Nehmen wir an, Sie möchten prüfen, ob die Variable x zwischen 10 und 20 liegt, in der Schule schreibt man einfach 10 < x < 20. In Processing müssen Sie das in zwei Vergleiche zerlegen, nämlich in 10 < x und x < 20. Damit "10 < x < 20" wirklich gilt, müssen beide Vergleich wahr sein. Diese Kombination nennt man das logische UND (engl. AND).
Das logische UND nennt man auch einen logischen Operator.
Im Code schreibt man für den UND-Operator ein doppeltes "käufmännisches Und", also
&&
:
int x = 5; if (10 < x && x < 20) { println("Yes!"); }
In der mathematischen Logik nennt man diese Operation auch Konjunktion und das Symbol für UND sieht so aus:
Das logische UND ist verwandt mit dem Konzept der Schnittmenge. Wenn Sie sich die zwei Mengen 10 < x und x < 20 vor Augen führen, dann ist (10 < x && x < 20) genau die Schnittmenge.
Logisches ODER
Der zweite wichtige Operator ist das logische ODER (engl. OR). Nehmen wir an, Sie wollen testen,
ob die x-Koordinate eines Objekts den Bildschirmbereich verlässt, der 1024 Pixel
breit ist. Dann testen Sie ob x < 0
ist oder x >= 1024
.
Das logische ODER schreibt man im Code mit zwei senkrechten Strichen
||
int x = 5; if (x < 0 || x >= 1024) { println("Oops!"); }
In der mathematischen Logik nennt man diese Operation auch Disjunktion und das Symbol für ODER sieht so aus: V
Das logische ODER ist verwandt mit dem Konzept der Vereinigungsmenge. Wenn Sie sich wieder die zwei Mengen 10 < x und x < 20 anschauen, dann ist (10 < x || x < 20) genau die Vereinigungsmenge.
Und wo ist dieses Zeichen | auf meiner Tastatur...?
Auf dem Mac mit ALT+7, unter Windows mit Alt Gr + <.
Trivia
Das Zeichen
|
wird in Unix-Kreisen auch pipe
genannt, weil damit die gleichnamige Operation in einer Unix-Shell
gekennzeichnet wird.
Negation
Mit dem Ausrufezeichen negieren Sie einen Ausdruck, d.h. Sie kehren den Wert um (true statt false bzw. false statt true). Das Ausrufezeichen nennt man auch den logischen Negationsoperator oder das logische NICHT (engl. NOT). Im Unterschied zu UND/ODER steht dieser Operator nicht zwischen zwei Ausdrücken, sondern vor einem einzigen Ausdruck.
Wenn Sie z.B.
den Vergleich
x < 10
negieren wollen, schreiben
Sie
! (x < 10)
. Das entspricht dann offensichtlich
x >= 10
, d.h. das könnte man eigentlich auch direkt so (ohne Negation) hinschreiben,
aber für komplexere Ausdrücke ist die Negation manchmal bequemer oder
lesbarer.
Nehmen wir an, Sie wollen das Beispiel oben "Objekt verlässt Bildschirm" einfach negieren. Das heißt, Sie wollen Code ausführen für den Fall, dass das Objekt noch auf dem Bildschirm ist, dann schreiben Sie:
int x = 5; if (! (x < 0 || x >= 1024)) { println("Bin auf dem Schirm!"); }
In der mathematischen Logik sieht das Symbol für Negation so aus: ¬
Sollten Sie sich fragen, wie man die obige Bedingung ohne Negation schreibt, kommen Sie
auf diesen Ausdruck:
x >= 0 && x < 1024
. Das heißt, wenn
man einen Ausdruck mit logischem ODER negiert, dann negiert man beide Einzelteile und
man "dreht den Operator um", d.h. aus ODER wird UND und umgekehrt. Das
nennt man das De Morganschen Gesetz.
! (x < 0 || x >= 1024) entspricht ! (x < 0) && ! (x >= 1024) entspricht x >=0 && x <1024
Komplexe Ausdrücke und Präzedenz
Sie können beliebig viele logische Ausdrücke mit UND/ODER kombinieren und mit NICHT negieren.
Wie wird ein solcher Ausdruck ausgewertet? Nehmen wir ein Beispiel mit zwei logischen Operatoren:
int k = 5; float f = 2.5; int t = 30; if (k > 0 && f < 10.0 || t > 100) { println("hurra"); }
Processing nimmt sich die Bedingung:
k > 0 && f < 10.0 || t > 100
Und setzt zunächst die Variablenwerte ein:
5 > 0 && 2.5 < 10.0 || 30 > 100
Dann werden die einzelnen Vergleiche aufgelöst:
true && true || false
Jetzt gehen wir von links nach rechts vor und lösen einen Operator nach dem nächsten, also zunächst das true && true, das wird zu true. Anschließend haben wir noch:
true || false
Dies wird wiederum aufgelöst zum Ergebnis:
true
In unserem Beispiel konnten wir von links nach rechts rechnen, aber das gilt nicht immer, denn der UND-Operator hat Priorität vor ODER.
Sehen wir uns das obige Beispiel leicht modifiziert an: das UND steht jetzt hinten, das ODER vorn:
k > 0 || f < 10.0 && t > 100
Wir setzen die Variablenwerte ein:
5 > 0 || 2.5 < 10.0 && 30 > 100
Und lösen die Vergleiche auf:
true || true && false
Jetzt kommt der entscheidende Unterschied: Statt von links nach rechts zu rechnen, müssen wir das UND vorziehen (das wird Präzedenz genannt):
true || true && false
Wir lösen als zunächst true && false auf zu false:
true || false
Dies wird wiederum aufgelöst zum Ergebnis:
true
Allgemein gesprochen verwendet Java bei booleschen (logischen) Ausdrücken ähnliche Regeln wie bei arithmetischen Ausdrücken (also Rechnungen mit +, -, *, /). Dabei gelten folgende Regeln:
Operator | Priorität | entspricht |
---|---|---|
! | 3 | unäres - (wie bei -3) |
&& | 2 | *, / |
|| | 1 | +, - |
In der Tabelle bedeutet eine höhere Priorität, dass der Operator als erstes ausgewertet wird. Das bedeutet: der Negationsoperator wird immer zuerst ausgewertet. Ferner gilt: ein UND wird immer vor ODER ausgewertet.
Wenn Sie folgenden Ausdruck vor sich haben:
a || b && !c || d
Wird dieser so ausgewertet, als gäbe es folgende Klammern:
(a || (b && (!c))) || d
Beispiel: Abprallender Ball
Wir schauen uns das Programm von oben, inklusive Geschwindigkeit, nochmal an:
Dank der Geschwindigkeit kann der Ball sowohl nach rechts (speed = 1) als auch nach links (speed = -1) fliegen. Daher möchten wir jetzt, dass der Ball von der rechten Wand abprallt. Das gleiche gilt natürlich auch für die linke Wand.
Man könnte das so formulieren:
Wenn der Ball den rechten Rand erreicht, soll er nach links weiterfliegen.
Der erste Teilsatz übersetzt sich wieder zu der Bedingung x > width
.
Der zweite Satz "nach links weiterfliegen" lässt sich realisieren, indem
man die Geschwindigkeit auf -1 setzt:
if (x > width) { speed = -1; }
Analog für den linken Rand:
Wenn der Ball den linken Rand erreicht, soll er nach rechts weiterfliegen.
Im Code:
if (x < 0) { speed = 1; }
Vorzeichen umdrehen
Wenn wir die Lösung allgemeiner betrachten, sehen wir, dass in beiden Fällen einfach das Vorzeichen der Geschwindigkeit umgedreht wird. Aus 1 wird -1 und aus -1 wird 1. Im Code lässt sich das Umdrehen des Vorzeichens ganz elegant formulieren:
speed = -speed;
Das Schöne an dieser Formulierung ist, dass es egal ist, welcher Wert in speed steht, ob 1, 15 oder 3002. Wenn der Wert negativ ist, wird er positiv. Ist er positiv, wird er negativ.
Der Code würde also wie folgt aussehen:
int x = 0; int speed = 1; void draw() { background(255); ellipse(x, 50, 20, 20); x = x + speed; if (x > width) { speed = -speed; } if (x < 0) { speed = -speed; } }
Zusammenfassen der If-Anweisungen
In dem oberen Code fällt auf, dass in beiden If-Anweisungen der exakt gleiche Code ausgeführt wird. Man könnte also auch sagen: wenn x > width oder x < 0 der Fall ist, dann drehe das Vorzeichen um. Also ein Fall für den booleschen Operator ODER:
int x = 0; int speed = 3; void draw() { background(255); ellipse(x, 50, 20, 20); x = x + speed; if (x < 0 || x > width) { speed = -speed; } }
Ein wichtiger Vorteil zu unserer ersten Lösung: wir können wieder beliebige Geschwindigkeitswerte nehmen, z.B. eben 3:
Sie können diesen Code relativ leicht auf zwei Dimensionen erweitern. Fügen Sie einfach entsprechende Variablen für die y-Richtung hinzu.
Visualisieren der Geschwindigkeit
Wir können die Geschwindigkeit als Linie zeichnen. So können wir sowohl die Größenordnung als auch die Richtung ablesen.
Wir zeichnen eine (rote) Linie vom Mittelpunkt des Balls und nehmen das zehnfache der Geschwindigkeit als Länge (sonst wäre die Linie nur 3 Pixel lang).
int x = 0; int speed = 3; void setup() { size(200, 100); strokeWeight(2); } void draw() { background(0); noStroke(); ellipse(x, 50, 20, 20); stroke(255, 0, 0); line(x, 50, x + 10*speed, 50); x = x + speed; if (x < 0 || x > width) { speed = -speed; } }
Probieren Sie den Code auch mit anderen Geschwindigkeiten.
Fingerübungen
a) Enthalten 1
Erstellen Sie drei float-Variablen a, b und x. Gehen Sie davon aus, dass a immer kleiner als b ist.
Schreiben Sie "x innerhalb" auf die Konsole, wenn x zwischen a und b liegt (die Werte a, b sollen dabei ausgeschlossen sein), sonst "x außerhalb". Testen Sie Ihr Programm mit entsprechenden Werten.
float a = 23; float b = 110; float x = 55; if (x > a && x < b) { println("x innerhalb"); } else { println("x außerhalb"); }
b) Enthalten 2
Erweitern Sie obiges Programm so, dass es auch funktioniert, wenn b kleiner als a ist.
float a = 110; float b = 23; float x = 55; if (x > a && x < b || x > b && x < a) { println("x innerhalb"); } else { println("x außerhalb"); }
c) Extrem
Erstellen Sie drei float-Variablen a, b und x. Gehen Sie davon aus, dass a immer kleiner als b ist.
Schreiben Sie "x extrem" auf die Konsole, wenn x außerhalb des Intervalls a und b liegt. Wenn x innerhalb des Intervalls liegt, passiert nichts. Verwenden Sie ein einfaches If (ohne Else-Teil).
float a = 23; float b = 110; float x = 250; if (x < a || x > b) { println("x extrem"); }
Übungsaufgaben
3.3 a) Human Resources Level 11 = easy
2 = relativ leicht
3 = mittel
4 = schwierig
5 = hart
Sie sind Personaler und möchten jemanden einstellen, der/die nicht zu jung ist (min. 20 Jahre) und nicht zu alt (max. 60 Jahre). Außerdem soll die Abschlussnote stimmen (besser als 3.0).
Ergänzen Sie den Code so, dass Ihr Programm "Einstellen!" ausgibt, wenn die obigen Bedingungen stimmen oder "Lieber nicht.", wenn nicht.
// Ändern Sie die Werte zum Testen int alter = 21; float note = 1.7;
Testen Sie Ihr Programm auch mit anderen Werten (alter=61, note=2.0 oder alter=33, note=3.3).
3.3 b) Human Resources 2 Level 21 = easy
2 = relativ leicht
3 = mittel
4 = schwierig
5 = hart
Sie sind Personaler bei einer Softwarefirma. Sie möchten die Sichtung der Bewerbungen automatisieren. Sie schauen sich die Abschlussnote (z.B. 1,7 oder 2,3) an und die Programmiererfahrung (zwischen 1 für "keine" und 5 für "hohe").
- Bewerber mit der Note 1 werden direkt eingestellt. Bewerber mit Programmiererfahrung der Stufe 5 werden auch direkt eingestellt, sofern sie mindestens die Note 3 haben.
- Bewerber mit Note 2 werden zum Gespräch eingeladen. Wenn Programmiererfahrung der Stufe 4 vorhanden ist, werden sie auch - unabhängig von der Note - eingeladen.
- Alle anderen werden abgelehnt
Schreiben Sie Code, der "einstellen" oder "zum Gespräch einladen" oder "ablehnen" ausgibt. Nutzen Sie die folgenden Variablen, deren Werte Sie natürlich mehrfach ändern müssen, um die Korrektheit Ihres Codes zu testen.
// Ändern Sie die Werte zum Testen float note = 2.3; int programmiererfahrung = 5;
3.3 c) Pulsieren Level 31 = easy
2 = relativ leicht
3 = mittel
4 = schwierig
5 = hart
Ein Kreis mit Durchmesser 50 wird stetig größer, bis er den Rand des Fensters erreicht, dann verkleinert er sich bis Durchmesser 50 usw.
Sehen Sie sich oben im Skript das Anwendungsbeispiel mit dem "an der Wand abprallen" an. Beim Abprallen haben Sie die x-Koordinate, die entweder größer oder kleiner wird. Bei der Aufgabe hier haben Sie genau das gleiche mit dem Durchmesser.
Wichtig: Achten Sie darauf, dass der Durchmesser nicht negativ wird. Geben Sie Ihre Variable für den Durchmesser zur Kontrolle auf der Konsole aus. Sie sollte nie negativ werden. Wenn Sie diesen Hinweis ignorieren, kann es sein, dass Ihr Programm nur aufgrund eines Artefakts "funktioniert", aber eigentlich falsch ist (und z.B. bei zukünftigen Versionen von Processing nicht mehr funktioniert).
3.3 d) Pulsierende Farbe Level 21 = easy
2 = relativ leicht
3 = mittel
4 = schwierig
5 = hart
Ein schwarzer Kreis wird stetig weißer bis er ganz weiß ist, dann wieder schwärzer, bis er ganz schwarz ist usw.
Auch hier ist das Schema wie in der vorigen Aufgabe: ein veränderlicher Wert (Grauwert) und eine Geschwindigkeit, die sich "umdreht".
3.3 e) Rote Zone Level 31 = easy
2 = relativ leicht
3 = mittel
4 = schwierig
5 = hart
Verwenden Sie folgenden Basiscode und verändern Sie ihn so, dass der Ball in der markierten Zone rot wird.
int x = 0; void draw() { background(0); // Linien zum Markieren der Zone stroke(255); line(25, 0, 25, height); line(75, 0, 75, height); // hier wird animiert... ellipse(x, 50, 20, 20); x++; if (x > width) { x = 0; } }
If
ändern: Es geht nur um die Farbe, rot oder weiß.
3.3 f) Rote Zone invers Level 11 = easy
2 = relativ leicht
3 = mittel
4 = schwierig
5 = hart
Verändern Sie den Code aus der obigen Aufgabe so, dass der Ball außerhalb der markierten Zone rot wird.
Wichtig: Lösen Sie diese Aufgabe, indem Sie die Bedingung ändern.
Zusammenfassung
-
Zwei boolesche Ausdrücke (wie z.B. die Vergleiche
x > 5
undx < 10
) lassen sich mit den logischen Operatoren UND bzw. ODER kombinieren. Das Gesamte ist wieder ein boolescher Ausdruck. -
Wir haben drei logische Operatoren kennen gelernt:
- UND: Der Ausdruck A && B (A und B) ist genau dann wahr, wenn sowohl A als auch B wahr sind.
- ODER: Der Ausdruck A || B (A oder B) ist genau dann wahr, wenn entweder A oder B (oder beide) wahr sind.
- NICHT: Der Ausdruck !A ist genau dann wahr, wenn A falsch ist.
-
Ein booleschen Ausdrucks
ist also entweder
- das Schlüsselwort
true
oderfalse
- ein Vergleich von Werten (z.B.
==
oder<=<>=<>)
- die logische Verknüpfung von zwei booleschen Ausdrücken mit
&&
oder||
- die Negation eines booleschen Ausdrucks mit
!
foo && (bar || doo)
). Das ist sehr praktisch, weil man mit wenigen Regeln auch sehr komplexe, verschachtelte Konstrukte erfassen kann. Man nennt eine solche Definition rekursiv. - das Schlüsselwort
3.4 Boolesche Variablen
Sie kennen jetzt Bedingungen in If-Anweisungen und sogar boolesche Ausdrücke mit
AND und OR. Boolesche Variablen sind ganz primitive Zeitgenossen, da sie lediglich
einen von zwei möglichen Werten speichern können:
true
oder
false
.
Wozu braucht man sowas? In Processing wollen Sie sich zum Beispiel einen Zustand merken. Wenn Sie zum Beispiel eine Animation haben, möchten Sie sich merken, ob die Animation laufen soll (play) oder anhalten (pause).
Nehmen wir mal eine einfache Animation:
int x = 0; void draw() { background(255); ellipse(x, 50, 20, 20); x++; // immer wieder von links reinkommen if (x >= 100) { x = 0; } }
Um einen einfachen play/pause Mechanismus zu implementieren, führen wir eine boolesche Variable
play
ein.
Wenn diese
true
ist, soll die Animation laufen. Wenn sie
false
ist, nicht:
int x = 0; boolean play = true; void draw() { background(255); ellipse(x, 50, 20, 20); // NEU: bewege dich nur, wenn play true ist if (play) { x++; } // immer wieder von links reinkommen if (x >= 100) { x = 0; } }
Es hat sich nicht viel geändert, aber Sie können die Variable play von Hand auf false setzen, dann bleibt der Ball links stehen. Beachten Sie, dass Sie nicht play == true in die Bedingung schreiben müssen (obwohl das auch funktionieren würde). Wenn play true ist, wird direkt true eingesetzt - das gleiche gilt für den Fall, dass play false ist. Keine Notwendigkeit also, nochmal == true hinzuschreiben.
Jetzt müssen Sie nur noch "zur Laufzeit", also während das Programm läuft, die Variable play umsetzen. Das funktioniert, indem Sie die folgende Funktion hinzufügen:
void keyPressed() { if (play) { play = false; } else { play = true; } }
Interaktives Feld:(erst auf das graue Feld klicken, dann Taste)
Sie setzen also die Variable play in Abhängigkeit von ihrem aktuellen Zustand, nämlich auf ihr 'Gegenteil'. In der Logik nennt man das auch die Negation ihres Zustands. Das kann man ganz elegant formulieren als:
void keyPressed() { play = !play; // setze play auf seine eigene Negation }
Das Negationszeichen funktioniert also ähnlich wie das Minuszeichen in der Arithmetik. Natürlich sind beide Code-Varianten völlig legitim und in Ordnung.
Boolesche Variablen und boolesche Ausdrücke
In eine boolesche Variable kann ein beliebiger boolescher Ausdruck per Zuweisung hineingetan werden. Im folgenden Beispiel wird der Ball in der x-Zone 30-70 rot gefärbt:
int x = 0; boolean inTheZone = false; void draw() { background(255); // boolescher Ausdruck inTheZone = x > 30 && x < 70; if (inTheZone) { fill(255, 0, 0); // rot } else { fill(255); // weiß } ellipse(x, 50, 20, 20); x++; }
Auch hier zeigt sich der Vorteil der Varible erst, wenn die Information an anderer Stelle bzw. zu anderer Zeit verwendet wird. Wollen Sie etwa per Tastendruck den Ball wieder auf x=0 setzen unter der Bedingung, dass der Ball in 'der Zone' ist, dann fügen Sie hinzu:
void keyPressed() { if (inTheZone) { x = 0; } }
Boolesche Variablen als Teil boolescher Ausdrücke
Boolesche Variablen können natürlich auch Bestandteil von booleschen Ausdrücken sein. Hier zwei Beispiele:
boolean foo = true; boolean goo = false; int x = 10; boolean ausdruck1 = foo && goo; boolean ausdruck2 = foo || x > 5; println(ausdruck1); println(ausdruck2);
Fingerübungen
a) Richtig/falsch
Gegeben sei eine boolesche Variable istKorrekt
. Wenn diese wahr ist, soll "richtig" ausgegeben werden, sonst "falsch".
Testen Sie Ihr Programm mit beiden möglichen Werten.
boolean istKorrekt = true; if (istKorrekt) { println("richtig"); } else { println("falsch"); }
b) Vergeich
Gegeben seien zwei boolesche Variablen foo
und bar
. Geben Sie "gleich" aus, wenn bei Variablen gleich sind, sonst "ungleich".
boolean foo = true; boolean bar = false; if (foo == bar) { println("gleich"); } else { println("ungleich"); }
c) Größer/kleiner
Erstellen Sie drei Variablen a (int), b (int) und agb (boolean). Setzen Sie a und b auf beliebigen Werte.
Die Variable agb soll true enthalten, wenn a größer b ist. Geben Sie agb auf der Konsole aus. Testen Sie Ihr Programm mit verschiedenen Werten für a und b.
int a = 5; int b = 10; boolean agb = a > b; println(agb);
Übungsaufgaben
3.4 a) Umschalten Level 11 = easy
2 = relativ leicht
3 = mittel
4 = schwierig
5 = hart
Kopieren Sie den folgenden Code. Sie dürfen nur die zwei Kommentare durch eigenen Code ersetzen!
boolean foo = true; // Hier kommt Ihr Code hin println(foo); // Gleicher Code wie oben println(foo);
Ergänzen Sie den Code so, dass die Variable foo
erst auf false und dann auf true geschaltet wird. An beiden Stellen soll der gleiche Code stehen!
Als Ausgabe sollten Sie sehen:
false true
Hinweis: Es gibt zwei Möglichkeiten. Entweder Sie verwenden ein if-else
oder Sie überlegen sich, wie Sie eine boolesche Variable "umkehren" - das funktioniert so ähnlich wie das Umkehren des Vorzeichens bei einer Zahl.
3.4 b) Now you see me... Level 21 = easy
2 = relativ leicht
3 = mittel
4 = schwierig
5 = hart
Schreiben Sie ein Programm, dass einen schwarz gefüllten Kreis malt. Wenn man auf die Maustaste drückt, verschwindet er. Beim nächsten Klick erscheint er usw.
Wichtig: Lösen Sie diese Aufgabe mit Hilfe einer booleschen Variable.
Interaktives Feld:(auf das Feld klicken)
3.4 c) Kreis oder Box Level 21 = easy
2 = relativ leicht
3 = mittel
4 = schwierig
5 = hart
Wo immer der Mauszeiger ist, wird ein weiß gefüllter Kreis gezeichnet (Durchmesser 30). Wenn Sie auf die Maustaste drücken, wird stattdessen ein schwarz gefülltes Quadrat gezeichnet (Kantenlänge 20). Wenn Sie wieder die Taste drücken, kommen wieder Kreise usw.
Interaktives Feld:(erst auf das graue Feld klicken)
3.4 d) horizontal oder vertikal Level 31 = easy
2 = relativ leicht
3 = mittel
4 = schwierig
5 = hart
Ein Kreis fliegt von links nach rechts und erscheint wieder am linken Rand, wenn er rechts rausfliegt. Wenn man die Maustaste drückt, fliegt der Kreis nach unten und erscheint wieder oben, wenn er den unteren Rand erreicht. Beim nächsten Klick fliegt er wieder horizontal usw.
Interaktives Feld:(erst auf das graue Feld klicken)
3.4 e) Fly-by Level 41 = easy
2 = relativ leicht
3 = mittel
4 = schwierig
5 = hart
Programmieren Sie das folgende interaktive Element. Es handelt sich um eine Box, die nach außen schwebt, sobald man mit der Maus klickt (egal wohin).
Für die Animation können Sie die Systemvariable frameCount
verwenden. Mit einer booleschen Variablen können Sie markieren, dass die Animation gerade läuft (oder eben nicht). Speichern Sie die Geschwindigkeit der Animation in einer Speed-Variablen, die Sie nach jeder Animation wieder "umdrehen".
Die abgerundeten Ecken bekommen Sie mit einem fünften Paramter bei rect
. Dieser ist der Radius der Abrundung (z.B. 10 Pixel).
Zusammenfassung
Boolesche Variablen können einen binären Zustand speichern, d.h. eine Variable enthält entweder den Wert true oder den Wert false. Eine boolesche Variable kann z.B. in einer If-Bedingung verwendet werden.
Ein Anwendungsbeispiel ist der Unterschied zwischen
"Play" und "Pause" bei einer Animation. Dies kann
in einer booleschen Variable play
gespeichert werden.
Hier würde true bedeuten "Objekt bewegt sich" und false "Objekt bewegt sich nicht".
Eine boolesche Variable kann mit dem Negationsoperator
invertiert werden, z.B. die Variable play
play = !play;
Eine boolesche Variable ist selbst ein boolescher Ausdruck, kann also allein in einer If-Bedingung stehen:
if (play) { x++; }
3.5 Tasten unterscheiden
Interaktion mit Tasten
Nachdem wir die If-Anweisung kennengelernt haben, können wir wesentlich differenzierter mit Benutzereingabe umgehen. Wir können z.B. unterscheiden, welche Taste gedrückt wurde.
Sie wissen, dass Sie auf einen Tastendruck reagieren können, indem Sie die Funktion keyPressed() einfügen. Der Code in dieser Funktion wird immer dann ausgeführt, wenn Sie eine beliebige Taste drücken:
void setup() {} void draw() {} void keyPressed() { println("Bravo! Eine Taste! Yeah!"); }
Datentyp char
Große Preisfrage: Welche Taste wurde gedrückt?
Dazu müssen wir erstmal den Datentyp char
kennenlernen (ein Datentyp ist sowas wie int und float).
char
steht für "character" (engl. für Schriftzeichen).
Eine solche Variable enthält genau ein Zeichen (Buchstaben, Zahlen
oder Zeichen wie , . # * etc.). Ein einzelnes Zeichen wird mit einfachen Anführungszeichen abgegrenzt . Hier einige Beispiele für char-Variablen.
char foo = 'a'; char boo = 'A'; // ist nicht gleich foo! char nochnZeichen = '#'; char machMalnPunkt = '.';
Systemvariable key
Die Systemvariable
key
enthält immer die zuletzt
gedrückte Taste. Wichtig: Wenn Sie 'a' drücken und die
Taste loslassen, enthält
key
immer noch 'a'. Im folgenden
Code ist das dennoch kein Problem, weil keyPressed() nur ein Mal
aufgerufen wird, wenn Sie die Taste 'a' drücken:
void setup() { } void draw() { } void keyPressed() { if (key == 'a') { println("A ha."); } }
Kontinuierliche Tastenabfrage (boolesche Variable keyPressed)
Problem mit dem obigen Code: Wenn Sie damit ein Spiel steuern wollen, reagiert Processing nicht, wie Sie möchten:
// Kreis-Steuerung: suboptimale Lösung int x = 50; void setup() { } void draw() { background(255); ellipse(x, 50, 20, 20); // Kreis malen } void keyPressed() { if (key == 'a') { x++; // Kreis nach rechts bewegen => es hakt leider } }Interaktives Feld:(erst auf das graue Feld klicken, dann 'a')
Auch hier kommt uns Processing zu Hilfe. Die Variable
keyPressed
ist eine boolesche Variable,
d.h. sie enthält entweder den Wert
true
oder
den Wert
false
. Diese Variable ist immer dann
true
,
wenn eine Taste im gedrückten Zustand ist. Das können wir ausnutzen, um
direkt im draw() unsere Tastaturabfrage zu machen:
int x = 50; void setup() { } void draw() { background(200); ellipse(x, 50, 20, 20); // Abfrage direkt in draw() statt in Funktion if (keyPressed) { if (key == 'a') { x++; // Kreis nach rechts bewegen } } }Interaktives Feld:(erst auf das graue Feld klicken, dann 'a')
Warum ist die keyPressed-Abfrage überhaupt notwendig? Wenn Sie sie weglassen, bewegt sich der Kreis
nach Drücken und Loslassen der Taste 'a' ständig weiter, da
key
immer die zuletzt
gedrückte Taste enthält.
Variable keyCode
Häufig wollen Sie Bewegung an die Cursortasten binden. Diese Tasten
lassen sich, ähnlich wie ENTER, BACKSPACE, ESCAPE etc. nicht
einfach zwischen zwei Anführungszeichen schreiben. Deshalb
verwendet man die Variable
keyCode
, die einen numerischen
Code für jede Taste enthält. Wenn Sie den keyCode von den Cursortasten
kennen, können Sie per Vergleich die Tasten abfragen:
int x = 50; void setup() { } void draw() { background(200); ellipse(x, 50, 20, 20); if (keyPressed) { if (keyCode == RIGHT) { x++; // Kreis nach rechts } if (keyCode == LEFT) { x--; // Kreis nach links } } }Interaktives Feld:(erst auf das graue Feld klicken, dann Cursortasten)
Im Code sehen Sie einen Vergleich von keyCode (enthält eine Zahl, nämlich den Code der zuletzt gedrückten Taste) und der Variablen RIGHT, welche die Zahl enthält, die die linke Cursortaste repräsentiert.
Interaktion mit Maustasten
Bei den Maustasten verhält es sich ähnlich wie mit der Tastatur. Sie haben wieder zwei Möglichkeiten.
Möglichkeit 1: Funktion mousePressed() schreiben
Sie können die Funktion
mousePressed()
schreiben. Diese wird immer dann aufgerufen,
wenn eine der Maustasten gedrückt wird:
void draw() { } void mousePressed() { println("hello"); }
Beachten Sie, dass Sie innerhalb des Grafikfensters klicken müssen.
Über die Systemvariable
mouseButton
können Sie unterscheiden, welche der Maustasten
gedrückt wurde:
void draw() { } void mousePressed() { if (mouseButton == LEFT) { println("hello"); } if (mouseButton == RIGHT) { println("again"); } if (mouseButton == CENTER) { println("in the middle"); } }
Ähnlich wie
keyCode
enthält diese Variable eine Zahl. Diese Zahl können Sie mit einer der Systemvariablen LEFT, RIGHT, CENTER
vergleichen, um zu prüfen, welche der drei Tasten gedrückt wurde.
Möglichkeit 2: boolesche Variable mousePressed in draw()
Analog zu keyPressed gibt es eine boolesche Variable mousePressed, die solange true ist, wie der Benutzer eine der Maustasten gedrückt hält. Das erlaubt eine kontinuierliche Abfrage innerhalb der draw()-Funktion wie hier:
void draw() { if (mousePressed) { if (mouseButton == LEFT) { println("hello"); } if (mouseButton == RIGHT) { println("again"); } if (mouseButton == CENTER) { println("in the middle"); } } }
Sie sehen, dass 60 Mal pro Sekunde die Ausgabe gemacht wird, sofern Sie eine der Tasten gedrückt halten.
Übungsaufgaben
Wir beginnen, das Spiel "Raincatcher" zu schreiben. Es geht darum, einen Eimer zu steuern, der Regentropfen einfängt.
Achten Sie darauf, Ihre Variablen "gut" zu benennen, damit Sie im weiteren Verlauf nicht den Überblick verlieren. Also besser eimerX statt ex oder x.
Das Auffangen der Tropfen können Sie im Aufgabenteil des nächsten Abschnitts finden.
3.5 a) Eimer Level 21 = easy
2 = relativ leicht
3 = mittel
4 = schwierig
5 = hart
Programmieren Sie einen "Eimer", den Sie mit den Cursortasten (links/rechts) steuern können. Achten Sie darauf, dass der Eimer flüssig nach links und rechts fährt, und dass er nie die Grenzen des Bildschirms verlässt.
(Sie müssen erst das Fenster anklicken, bevor Sie die Tasten verwenden können. Wenn Sie über dieser Zeile eine Lücke sehen, probieren Sie Firefox.)
3.5 b) Tropfen Level 41 = easy
2 = relativ leicht
3 = mittel
4 = schwierig
5 = hart
Programmieren Sie die Tropfen: Drei Tropfen (oder andere Gegenstände) fliegen von oben nach unten. Der x- und y-Startpunkt sind beide zufällig zu Beginn. Sobald ein Tropfen den Boden erreicht, verschwindet er und ein "neuer" Tropfen erscheint an zufälliger Position am oberen Rand, mit einer zufälligen neuen Farbe.
Vermeiden Sie es, dass Tropfen am Rand "angeschnitten" erscheinen.
Tipp: Beginnen Sie mit einem einzigen Tropfen.
(Sie müssen erst das Fenster anklicken, bevor Sie die Tasten verwenden können. Wenn Sie über dieser Zeile eine Lücke sehen, probieren Sie Firefox.)
3.5 c) Gate Level 31 = easy
2 = relativ leicht
3 = mittel
4 = schwierig
5 = hart
Programmieren Sie ein "Tor", das Sie mit den Cursortasten (hoch/runter) steuern können. Achten Sie darauf, dass das Tor nicht noch oben/unten verschwinden kann.
(Sie müssen erst das Fenster anklicken, bevor Sie die Tasten verwenden können. Wenn Sie über dieser Zeile eine Lücke sehen, probieren Sie Firefox.)
Zusammenfassung
Sie haben gesehen, dass Sie prinzipiell zwei Möglichkeiten haben, eine Tastaturabfrage
durchzuführen: (1) indem Sie eine eigene Funktion keyPressed()
schreiben oder (2) indem Sie in draw() eine
If-Anweisung einbauen, die auf die boolesche Variable keyPressed
reagiert.
In beiden Fällen können Sie mit weiteren If-Anweisungen zwischen verschiedenen Tasten unterscheiden.
Dabei verwenden Sie die Systemvariable
key
für die 'normalen' Tasten (a, b, c, ...)
und die Variable
keyCode
für solche Tasten, die kein Zeichen auf dem Bildschirm
produzieren (ESCAPE, ENTER, Cursortasten etc.).
Beachten Sie, dass die Variable key
vom Typ char
ist (nicht String), so
dass Sie key == 'a'
schreiben müssen
(einfache Anführungszeichen).
Die Abfrage der Maustasten funktioniert analog zu der Tastaturabfrage. Sie verwenden die
Funktion mousePressed()
, wenn Sie nur einmal auf den Druck reagieren wollen.
Sie verwenden die boolesche Variable mousePressed
innerhalb von draw(), wenn
Sie eine kontinuierliche Steuerung benötigen (z.B. Dauerfeuer in einem Shooter oder
eine fließende Links-Rechts-Bewegung über Maustasten).
3.6 Kollisionserkennung
In diesem Kapitel überlegen wir uns, wie einfach interaktive Elemente funktionieren, wie Sie sie für ein grafisches Interface (GUI, graphical user interface) und Spiele benötigen würden.
Das einfachste interaktive Element ist eine Form, die "aktiv" wird, sobald der Mauszeiger auf ihr liegt, und "inaktiv", sobald der Mauszeiger wieder fort ist.
Dazu müssen wir zunächst wissen, wie wir feststellen, dass der Mauszeiger auf einem Objekt liegt. Das nennt man auch Kollisionerkennung und ist in Computerspielen von hoher Bedeutung.
Punkt-Rechteck
Kollisionserkennung zwischen einem Punkt (z.B. dem Mauszeiger) und einem Rechteck, das parallel zu den Achsen des Koordinatensystems liegt, ist sehr einfach.
Als Rechteck nehmen wir ein Rechteck mit Eckpunkt (rx, ry) und der Größe rwidth und rheight. Den Punkt, für den wir die Kollision berechnen wollen, nennen wir (x, y).
Wir überlegen uns das Problem zunächst nur für die x-Achse. Wenn wir nur die x-Achse betrachten, heißt "Kollision", dass der Wert x innerhalb des Bereichs rx und rx + rwidth liegt. Wenn das der Fall ist, liegt unser Punkt also schonmal innerhalb des korrekten x-Bereichs.
Anschließend betrachten wir die y-Achse. Auch da gilt: "Kollision" heißt hier, dass der y-Wert des Punkts zwischen den Werten ry und ry + height liegt.
Insgesamt schließen wir also: Der Punkt liegt im Rechteck, wenn die folgenden zwei Bedingungen gleichzeitig gelten:
rx <= x <= rx + rwidth ry <= y <= ry + rheight
Im Code sieht das so aus (statt x, y finden Sie mouseX, mouseY):
// interface_1 // Kollision mit Rechteck (Selektion per Rollover) int rx = 50; int ry = 50; int rwidth = 150; // Breite int rheight = 200; // Höhe void setup() { size(300, 300); noStroke(); } void draw() { // setze Füllfarbe ... if (rx <= mouseX && mouseX <= rx + rwidth && ry <= mouseY && mouseY <= ry + rheight) { // ... wenn Mauszeiger im Rechteck => rot fill(255, 0, 0); } else { // ... sonst: weiß fill(255); } rect(rx, ry, rwidth, rheight); }
Interaktives Feld:(gehen Sie mit der Maus über das Rechteck!)
Punkt-Kreis
Kollisionserkennung zwischen einem Punkt und einem Kreis ist sogar noch einfacher. Dazu vergleicht man die Distanz des Punkts (x, y) mit dem Mittelpunkt (cx, cy) des Kreises.
Ist die Distanz geringer als der Radius, so ist der Punkt im Kreis:
dist(x, y, cx, cy) < radius
Die Processing-Funktion dist()
berechnet den Abstand zweier Punkte, die mit insgesamt vier Parametern angegeben werden. Im folgenden Code nehmen wieder mouseX, mouseY den Platz von x, y ein und der Radius errechnet sich aus diameter/2.
// interface_2 // Kollision mit Kreis (Selektion per Rollover) int cx = 170; int cy = 160; int diameter = 180; // Durchmesser void setup() { size(300, 300); noStroke(); } void draw() { // setze Füllfarbe ... if (dist(mouseX, mouseY, cx, cy) < diameter/2) { // ... wenn Mauszeiger im Rechteck => rot fill(255, 0, 0); } else { // ... sonst: weiß fill(255); } ellipse(cx, cy, diameter, diameter); }
Interaktives Feld:(gehen Sie mit der Maus über den Kreis!)
Weitere Kollisionen
Mit den obigen Techniken können Sie also Kollisionen zwischen Punkt-Rechteck und Punkt-Kreis erkennen. Damit lässt sich schon eine Menge anfangen.
Wer aber auch wissen will, wie man Kollisionen zwischen
- Rechteck-Rechteck
- Kreis-Rechteck
- Punkt-Linie
- Linie-Linie
- etc.
erkennen kann, kann sich die folgende Webseite mit interaktiven Processing-Beispielen ansehen: Collision Detection by Jeff Thompson.
Als Beispiel die Kollision Rechteck-Rechteck (siehe Thompsons Collision Rectangle-Rectangle).
Interaktives Feld:
Übungsaufgaben
3.6 a) Farb-Buttons Level 31 = easy
2 = relativ leicht
3 = mittel
4 = schwierig
5 = hart
Erstellen Sie drei weiße Buttons mit den Beschriftungen "Rot", "Grün" und "Blau".
Solange der Mauszeiger über einem der Buttons schwebt, soll der entsprechende Button hellgrau sein.
Wenn der User auf einen der Buttons klickt, soll der Hintergrund die entsprechende Farbe annehmen.
Wenn der User außerhalb der Buttons auf den Hintergrund klickt, wird dieser wieder grau.
(Wenn Sie über dieser Zeile eine Lücke sehen, probieren Sie Firefox.)
3.6 b) Überlappende Buttons Level 31 = easy
2 = relativ leicht
3 = mittel
4 = schwierig
5 = hart
Sie haben zwei Quadrate mit Seitenlänge 50px. Färben Sie den "Mauszeiger" (Kreis) farbig ein, sobald er innerhalb der Bereiche ist. Konkret: rot im ersten Quadrat, grün im zweiten Quadrat und blau in der Schnittmenge.
Verwenden Sie den Basiscode und versuchen Sie, den Code so zu schreiben, dass das Programm auch funktioniert, wenn man die Werte von x1, y1, x2, y2 ändert.
Interaktives Feld:
Basiscode:
int x1 = 30; int y1 = 10; int x2 = 10; int y2 = 40; void draw() { background(255); noFill(); rect(x1, y1, 50, 50); rect(x2, y2, 50, 50); ellipse(mouseX, mouseY, 20, 20); }
min
und max
die Bedingung für das entsprechende If
aufstellen? (Schauen Sie in der Processing-Referenz nach diesen Funktionen...)
3.6 c) Raincatcher Level 51 = easy
2 = relativ leicht
3 = mittel
4 = schwierig
5 = hart
Jetzt können Sie Ihre Regentropfen einsammeln (siehe Aufgaben 3.5a Eimer und 3.5b Tropfen)! Zählen Sie einen Punkt hoch, wenn Sie einen Topfen fangen. Zählen Sie ein "Leben" runter, wenn Ihnen ein Tropfen entwischt.
Beginnen Sie evtl. nur mit einem Tropfen. Das Programm wird bereits recht umfangreich. Achten Sie also auf gute Kommentierung und gute Benennung Ihrer Variablen.
(Sie müssen erst das Fenster anklicken, bevor Sie die Tasten verwenden können. Wenn Sie über dieser Zeile eine Lücke sehen, probieren Sie Firefox.)
3.6 d) Kollision Punkt-Linie Level 31 = easy
2 = relativ leicht
3 = mittel
4 = schwierig
5 = hart
Gegeben sind ein Punkt a und eine Linie b. Die Linie können Sie mit den Pfeiltasten bewegen.
Ergänzen Sie den Basiscode unten so, dass immer wenn der Punkt "innerhalb" der Linie liegt, die Linie rot gefärbt erscheint.
(Sie müssen erst das Fenster anklicken, bevor Sie die Tasten verwenden können.)
Hier ist der Basiscode. Konzentrieren Sie sich ganz bewusst auf die x-Werte.
float ax = 50; // x-Position von Punkt a float bx = 5; // x-Position des Startpunkts der Linie b float bwidth = 30; // Breite der Linie b void draw() { background(0); strokeWeight(5); stroke(0,255,0); point(ax, 50); stroke(255); // HIER IHR CODE line(bx, 60, bx+bwidth, 60); if (keyPressed) { if (keyCode == LEFT) { bx -= 2; } else if (keyCode == RIGHT) { bx += 2; } } }
3.6 e) Kollision Linie-Linie Level 31 = easy
2 = relativ leicht
3 = mittel
4 = schwierig
5 = hart
Wir erweitern das Szenario aus der letzten Aufgabe so, dass a jetzt auch eine Linie ist. Wie müssen Sie den Code erweitern, damit die untere Linie b immer dann rot wird, wenn sich die beiden Linien überschneiden?
(Sie müssen erst das Fenster anklicken, bevor Sie die Tasten verwenden können.)
Und wieder Basiscode:
float ax = 60; // x-Position des Startpunkts der Linie a float awidth = 30; // Breite der Linie a float bx = 5; // x-Position des Startpunkts der Linie b float bwidth = 40; // Breite der Linie b void setup() { size(150, 100); } void draw() { background(0); strokeWeight(4); stroke(0,255,0); line(ax, 50, ax+awidth, 50); stroke(255); // HIER IHR CODE line(bx, 60, bx+bwidth, 60); if (keyPressed) { if (keyCode == LEFT) { bx -= 2; } else if (keyCode == RIGHT) { bx += 2; } } }
3.6 f) Pong Level 41 = easy
2 = relativ leicht
3 = mittel
4 = schwierig
5 = hart
Programmieren Sie den Spiele-Klassiker Pong.
Hier sehen Sie die Ein-Spieler-Version, wo man versuchen muss, den Ball nicht auf den Boden aufkommen zu lassen.
(Sie müssen erst das Fenster anklicken, bevor Sie die Tasten verwenden können. Wenn Sie über dieser Zeile eine Lücke sehen, probieren Sie Firefox.)
Tipps: Um die Kollision zwischen "Ball" und dem Balken zu berechnen, helfen Ihnen vielleicht die zwei vorigen Aufgaben. Um den Zustand "Game Over" vom eigentlichen Spiel zu trennen, verwenden Sie eine boolesche Variable gameOver
, die anfangs false
ist. In draw() packen Sie dann gleich zu Beginn ein if (gameOver) ...
, wo entweder der Schriftzug "Press SPACE" gezeigt wird oder (im Else-Teil) das Spiel verarbeitet wird.
3.6 g) GateGame Level 41 = easy
2 = relativ leicht
3 = mittel
4 = schwierig
5 = hart
Programmieren Sie das folgende Spiel: Ein Objekt kommt wiederholt von links nach rechts geflogen (die Höhe ist zufällig). Der Spieler steuert ein Tor. Wenn das Objekt durch das Tor fliegt, bekommt der Spieler einen Punkt. Wenn das Objekt nicht das Tor trifft, leuchtet es rot und der Spieler verliert einen Punkt.
Mit der Leertaste setzt man den Spielstand auf Null.
(Sie müssen erst das Fenster anklicken, bevor Sie die Tasten verwenden können.)
3.6 h) Drag and drop Level 51 = easy
2 = relativ leicht
3 = mittel
4 = schwierig
5 = hart
Sie sollen "Drag and drop" realisieren, d.h. wenn die Maus über dem Kreis ist, kann man den Kreis bewegen, indem man die Maus bei gedrückter Taste bewegt.
Probieren Sie zunächst die einfache Variante. Hier springt der Kreis, sobald Sie mit der Maus über dem Kreis sind und Sie die Maustaste drücken, mit seinem Mittelpunkt zur Maus.
Bei dem folgenden Programm wird der Kreis rot eingefärbt, sobald der Mauszeiger über dem Kreis ist. Der gelbe Rand erscheint, wenn zusätzlich die Maustaste gedrückt wird. Verzichten Sie gern auf den Rand und konzentrieren Sie sich auf das Drag.
Dass der Kreis immer mit dem Mittelpunkt zur Maus springt ist gerade bei größeren Objekten nicht schön. Jetzt bewegen Sie den Kreis so, dass er sich immer relativ zur Mauszeigerbeweung bewegt. Verwenden Sie dazu zum Beispiel pmouseX
und pmouseY
, das ist die Mausposition des vorhergehen Frames.
3.6 i) Fly-by II Level 51 = easy
2 = relativ leicht
3 = mittel
4 = schwierig
5 = hart
Greifen Sie die Aufgabe Fly-by nochmal auf. Jetzt soll nur das Element ausgefahren werden, auf dem sich die Maus befindet.