api:projects:pong:start
Unterschiede
Hier werden die Unterschiede zwischen zwei Versionen angezeigt.
Beide Seiten der vorigen RevisionVorhergehende ÜberarbeitungNächste Überarbeitung | Vorhergehende Überarbeitung | ||
api:projects:pong:start [2020/12/29 16:41] – Martin Pabst | api:projects:pong:start [2021/12/29 11:29] (aktuell) – Externe Bearbeitung 127.0.0.1 | ||
---|---|---|---|
Zeile 1: | Zeile 1: | ||
- | ====== | + | ====== |
- | Pong ist eines der ersten Computerspiele. Es wurde 1972 von Atari entwickelt, [[https:// | + | {{ : |
+ | <WRAP center round info 50%> | ||
+ | Das 1972 von Atari veröffentlichte Pong war eines der ersten Computerspiele, [[https:// | ||
+ | Zwei Spieler steuern je einen Schläger am linken bzw. rechten Bildschirmrand und versuchen, einen Ball so abprallen | ||
+ | </ | ||
+ | \\ | ||
+ | ===== Programmierung des Schlägers ===== | ||
+ | {{ youtube> | ||
+ | < | ||
+ | <div class=" | ||
+ | |||
+ | <script type=" | ||
+ | new Schläger(0, | ||
+ | new Schläger(800 - 20, 20, 200, Key.ArrowUp, | ||
+ | |||
+ | class Schläger extends Rectangle { | ||
+ | |||
+ | | ||
+ | | ||
+ | |||
+ | | ||
+ | |||
+ | | ||
+ | super(x, | ||
+ | | ||
+ | this.tasteRauf = tasteRauf; | ||
+ | this.tasteRunter = tasteRunter; | ||
+ | | ||
+ | setFillColor(Color.white); | ||
+ | | ||
+ | } | ||
+ | |||
+ | | ||
+ | if(isKeyDown(tasteRauf)) { | ||
+ | | ||
+ | move(0, -dy); | ||
+ | } | ||
+ | } | ||
+ | | ||
+ | if(isKeyDown(tasteRunter)) { | ||
+ | | ||
+ | move(0, dy); | ||
+ | } | ||
+ | } | ||
+ | | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | </ | ||
+ | |||
+ | </ | ||
+ | |||
+ | |||
+ | | ||
+ | ===== Programmierung des Balls ===== | ||
+ | {{ youtube> | ||
< | < | ||
- | <div class=" | ||
- | <script type=" | + | <div class=" |
- | // Im Hauptprogramm wird nur ein Pong-Objekt instanziert. Dadurch | + | |
- | // wird der Konstruktor der Klasse Pong aufgerufen, in dem | + | <script type=" |
- | // die weiteren Objekte | + | Schläger links = new Schläger(0, |
+ | Schläger rechts = new Schläger(800 - 20, 20, 200, Key.ArrowUp, | ||
+ | new Ball(20, 400, 300, links, rechts); | ||
+ | |||
+ | class Schläger extends Rectangle { | ||
+ | |||
+ | | ||
+ | | ||
+ | |||
+ | | ||
+ | |||
+ | | ||
+ | super(x, | ||
+ | |||
+ | this.tasteRauf = tasteRauf; | ||
+ | this.tasteRunter = tasteRunter; | ||
+ | |||
+ | setFillColor(Color.white); | ||
+ | |||
+ | } | ||
+ | |||
+ | | ||
+ | if(isKeyDown(tasteRauf)) { | ||
+ | | ||
+ | move(0, | ||
+ | } | ||
+ | } | ||
+ | |||
+ | if(isKeyDown(tasteRunter)) { | ||
+ | | ||
+ | move(0, dy); | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | <script type=" | ||
+ | class Ball extends Rectangle { | ||
+ | |||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | |||
+ | |||
+ | | ||
+ | super(x - breite | ||
+ | | ||
+ | this.schlägerLinks = schlägerLinks; | ||
+ | this.schlägerRechts = schlägerRechts; | ||
+ | |||
+ | setzeZufallsGeschwindigkeit(); | ||
+ | } | ||
+ | |||
+ | | ||
+ | |||
+ | move(vx, vy); | ||
+ | |||
+ | if(getCenterY() < getWidth() | ||
+ | vy = vy * (-1); | ||
+ | } | ||
+ | |||
+ | if(getCenterY() > 600 - getWidth() | ||
+ | vy = vy * (-1); | ||
+ | } | ||
+ | |||
+ | if(collidesWith(schlägerLinks) || collidesWith(schlägerRechts)) { | ||
+ | vx = vx * (-1); | ||
+ | } | ||
+ | |||
+ | if(getCenterX() < - getWidth() / 2) { | ||
+ | | ||
+ | | ||
+ | } | ||
+ | |||
+ | if(getCenterX() > 800 + getWidth() / 2) { | ||
+ | | ||
+ | | ||
+ | } | ||
+ | |||
+ | } | ||
+ | |||
+ | |||
+ | void setzeZufallsGeschwindigkeit() { | ||
+ | |||
+ | double r = Math.random() * 5 + 5; | ||
+ | double winkelGrad = Math.random() * 50 + 20; | ||
+ | double winkelRad = winkelGrad / 180 * Math.PI; | ||
+ | |||
+ | vx = r * Math.cos(winkelRad); | ||
+ | vy = - r * Math.sin(winkelRad); | ||
+ | |||
+ | if(Math.random() < 0.5) { | ||
+ | vx = -vx; | ||
+ | } | ||
+ | |||
+ | if(Math.random() < 0.5) { | ||
+ | vy = -vy; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | </ | ||
+ | |||
+ | </ | ||
+ | \\ | ||
+ | ===== Hauptprogramm, | ||
+ | {{ youtube> | ||
+ | < | ||
+ | |||
+ | <div class=" | ||
+ | |||
+ | <script type=" | ||
new Pong(); | new Pong(); | ||
- | class Pong { | + | class Pong extends Actor { |
- | private | + | Text punkteanzeige; |
- | private | + | |
- | private | + | Text großeAnzeige; |
+ | |||
+ | int punkteLinks = 0; | ||
+ | int punkteRechts = 0; | ||
+ | |||
+ | | ||
+ | |||
+ | Schläger | ||
+ | | ||
+ | Ball ball; | ||
+ | |||
+ | | ||
+ | super(); | ||
+ | links = new Schläger(0, | ||
+ | rechts = new Schläger(800 - 20, 20, 200, Key.ArrowUp, | ||
+ | ball = new Ball(20, 400, 300, links, rechts, this); | ||
- | | + | punkteanzeige = new Text(400, 20, 64, "" |
+ | punkteanzeige.setAlignment(Alignment.center); | ||
+ | punkteanzeige.setFillColor(Color.white); | ||
+ | punkteAnzeigen(); | ||
- | // In diesen Attributen wird der Spielstand gespeichert: | + | großeAnzeige |
- | | + | |
- | private int punkteRechts = 0; | + | großeAnzeige.setFillColor(Color.white); |
- | /* | + | setZustand("Vor dem Spiel"); |
- | * Im Konstruktor werden die Schläger, der Ball und die Punkteanzeige | + | |
- | * instanziert. Danach ist das Hauptprogramm beendet. Weiter gehts in | + | |
- | * den act-Methoden der Schläger und des Balls, die 30-mal pro Sekunde | + | |
- | * vom Browser aufgerufen werden. | + | |
- | */ | + | |
- | | + | |
- | schlägerLinks = new Schläger(0, | + | |
- | schlägerRechts = new Schläger(800 - 30, 100, " | + | |
- | ball = new Ball(schlägerLinks, | + | |
- | punkteAnzeige = new Text(400, 10, 48, "0 : 0"); | + | |
- | punkteAnzeige.setAlignment(Alignment.center); | + | |
- | punkteAnzeige.setFillColor(Color.white); | + | |
} | } | ||
- | /* | + | public void onKeyTyped(String key) { |
- | * Zeigt den aktuellen Punktestand an | + | |
- | */ | + | setZustand(" |
- | private void zeigePunkte() { | + | } else |
- | | + | if(key == " " && zustand == "Game over") { |
+ | setZustand("Vor dem Spiel"); | ||
+ | } | ||
} | } | ||
- | /* | + | |
- | * Wird von der act-Methode des Balls aufgerufen, wenn der Ball den rechten | + | |
- | * Bildschirmrand überschreitet. | + | |
- | */ | + | if((punkteLinks == 3 || punkteRechts == 3) && zustand == "Im Spiel" |
- | | + | |
- | punkteLinks++; | + | } |
- | | + | |
} | } | ||
- | /* | + | void punktFürRechtenSpieler() { |
- | * Wird von der act-Methode des Balls aufgerufen, wenn der Ball den linken | + | |
- | * Bildschirmrand überschreitet. | + | |
- | */ | + | |
- | | + | |
punkteRechts++; | punkteRechts++; | ||
- | | + | |
} | } | ||
+ | void punktFürLinkenSpieler() { | ||
+ | punkteLinks++; | ||
+ | punkteAnzeigen(); | ||
+ | } | ||
+ | |||
+ | void setZustand(String neuerZustand) { | ||
+ | | ||
+ | if(neuerZustand == "Vor dem Spiel" | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } else if(neuerZustand == "Im Spiel" | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } else if(neuerZustand == "Game over") { | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | |||
+ | zustand = neuerZustand; | ||
+ | |||
+ | } | ||
} | } | ||
</ | </ | ||
- | <script type=" | + | <script type=" |
- | /** | + | |
- | * Ein Objekt der Klasse Schläger stellt den Schläger als Rechteck dar und bewegt ihn nach | + | |
- | * oben/unten wenn die Taste tasteHoch/ | + | |
- | */ | + | |
class Schläger extends Rectangle { | class Schläger extends Rectangle { | ||
- | private | + | |
- | private | + | |
+ | |||
+ | | ||
- | private int geschwindigkeit = 8; // Geschwindigkeit des Schlägers in Pixel pro 1/30 s | + | |
- | + | super(x,(600 - höhe) / 2, breite, höhe); | |
- | /** | + | |
- | * Im Konstruktor wird das Schläger-Rechteck initialisiert. Damit die Schläger-Klasse sowohl zum | + | this.tasteRauf |
- | * Erzeugen des linken als auch des rechten Schläger-Objekts verwendet werden kann, werden dem Konstruktor | + | |
- | * die x-Koordinate des linken Randes sowie die zwei Tasten zur Steuerung des Schlägers als Parameter übergeben. | + | |
- | */ | + | |
- | | + | |
- | super(links, 0, 20, höhe); | + | |
- | this.tasteHoch | + | |
this.tasteRunter = tasteRunter; | this.tasteRunter = tasteRunter; | ||
- | | + | |
setFillColor(Color.white); | setFillColor(Color.white); | ||
+ | | ||
} | } | ||
- | /** | ||
- | * Die Methode act wird 30-mal pro Sekunde vom Browser aufgerufen. | ||
- | */ | ||
| | ||
- | | + | if(isKeyDown(tasteRauf)) { |
- | * Die Klasse Rectangle besitzt eine Methode isKeyDown, die genau dann true zurückgibt, | + | |
- | * eine bestimmte Taste gerade gedrückt ist. | + | |
- | */ | + | |
- | | + | |
- | // Falls der Schläger noch nicht am oberen Rand anschlägt, bewege ihn hoch: | + | |
| | ||
- | move(0, -geschwindigkeit); | + | move(0, -dy); |
} | } | ||
} | } | ||
| | ||
if(isKeyDown(tasteRunter)) { | if(isKeyDown(tasteRunter)) { | ||
- | // Falls der Schläger noch nicht am unteren Rand anschlägt, bewege ihn runter: | + | |
- | if(getCenterY() < getWorld().getHeight() | + | move(0, |
- | move(0, | + | |
} | } | ||
} | } | ||
+ | | ||
} | } | ||
- | + | } | |
- | } | + | |
</ | </ | ||
- | <script type=" | + | <script type=" |
- | /** | + | |
- | * Die Klasse Ball stellt den Ball am Bildschirm dar, bewegt ihn, reagiert auf Kollision | + | |
- | * mit den Schlägern und dem oberen/ | + | |
- | * den sichtbaren Bereich rechts oder links verlässt und veranlasst dann die Änderung des Spielstands | + | |
- | * sowie einen Abstoß in der Mitte des Bildschirms. | + | |
- | */ | + | |
class Ball extends Rectangle { | class Ball extends Rectangle { | ||
- | private | + | |
- | private | + | |
+ | | ||
+ | | ||
+ | Pong pong; | ||
- | | ||
- | private Schläger schlägerLinks; | + | Ball(double breite, double x, double y, Schläger schlägerLinks, |
- | | + | |
- | + | super(x - breite / 2, y - breite / 2, breite, breite); | |
- | | + | |
- | + | ||
- | /** | + | |
- | * Der Konstruktor der Klasse Ball initialisiert das Ball-Rechteck. | + | |
- | */ | + | |
- | | + | |
- | super(400 - breite / 2, 300 - breite / 2, breite, breite); // Aufruf des Konstruktors der Oberklasse Rectangle | + | |
- | setzeZufallsGeschwindigkeit(); | + | |
setFillColor(Color.white); | setFillColor(Color.white); | ||
- | |||
- | this.schlägerRechts = schlägerRechts; | ||
this.schlägerLinks = schlägerLinks; | this.schlägerLinks = schlägerLinks; | ||
+ | this.schlägerRechts = schlägerRechts; | ||
this.pong = pong; | this.pong = pong; | ||
+ | |||
+ | setzeZufallsGeschwindigkeit(); | ||
} | } | ||
- | /** | ||
- | * Die Methode act wird vom Browser 30-mal pro Sekunde aufgerufen. Sie bewegt den Ball und | ||
- | * reagiert auf Kollisionen mit den Schlägern, dem oberen/ | ||
- | * des Grafikbereichs rechts/ | ||
- | */ | ||
| | ||
- | move(vx, vy); // bewegt den Ball | ||
| | ||
- | | + | if(pong.zustand != "Im Spiel") { |
- | | + | return; |
- | vy *= -1; | + | } |
- | } | + | |
- | | + | |
- | testKollisionMitSchläger(schlägerRechts); | + | |
- | | + | if(getCenterY() < getWidth() / 2) { |
- | // dann lassen wir kein Abprallen mit dem Schläger mehr zu, sondern werten es als Punkt für den | + | vy = vy * (-1); |
- | // rechten Spieler: | + | |
- | | + | |
- | setCenter(400, | + | |
- | | + | |
- | | + | |
} | } | ||
- | | + | |
- | // ... entsprechend für den rechten Bildschirmrand: | + | |
- | if(getCenterX() > getWorld().getWidth() - schlägerRechts.getWidth() | + | vy = vy * (-1); |
- | setCenter(400, 300); | + | } |
+ | |||
+ | if(collidesWith(schlägerLinks) || collidesWith(schlägerRechts)) { | ||
+ | vx = vx * (-1); | ||
+ | } | ||
+ | |||
+ | if(getCenterX() < - getWidth() / 2) { | ||
+ | pong.punktFürRechtenSpieler(); | ||
| | ||
+ | | ||
+ | } | ||
+ | |||
+ | if(getCenterX() > 800 + getWidth() / 2) { | ||
| | ||
+ | | ||
+ | | ||
} | } | ||
} | } | ||
+ | |||
- | private | + | |
- | | + | |
- | | + | |
- | | + | double |
- | if(Math.abs(vy) < 10) { | + | |
- | vy -= dy / schläger.getHeight() * 6; | + | |
- | } | + | vx = r * Math.cos(winkelRad); |
- | System.playSound(Sound.pong_f); | + | vy = - r * Math.sin(winkelRad); |
+ | |||
+ | | ||
+ | vx = -vx; | ||
} | } | ||
- | } | ||
- | /** | + | |
- | * Diese Methode gibt dem Ball eine zufällige Geschwindigkeit. Dabei dürfen aber keine Geschwindigkeitsvektoren | + | |
- | * entstehen, die zu " | + | |
- | */ | + | |
- | | + | |
- | double v = Math.random() * 4 + 8; // Betrag der Geschwindigkeit zwischen 8 und 12 (Pixel je 1/30 s) | + | |
- | double winkel = Math.random() * Math.PI / 4 + Math.PI / 8; // Winkel zwischen 22,5 und 67,5 Grad | + | |
- | vx = Math.cos(winkel) * v; | + | |
- | vy = Math.sin(winkel) * v; | + | |
- | | + | |
- | | + | |
} | } | ||
- | |||
} | } | ||
</ | </ | ||
+ | |||
</ | </ | ||
+ | |||
</ | </ | ||
+ | | ||
+ | ===== Aufgaben ===== | ||
+ | Erweitere das PONG-Spiel folgendermaßen: | ||
+ | - Wenn der Ball am oberen oder unteren Rand abprallt, soll ein tiefer Ton zu hören sein (Anweisung '' | ||
+ | - Oft dauert es ewig, bis ein Tor erzielt wird. Je länger der Ball im Spiel ist, desto schneller soll er werden. Gleichzeitig soll auch die Geschwindigkeit der Schläger zunehmen. Sobald ein Tor erzielt wird, soll die Geschwindigkeit der Schläger wieder auf den ursprünglichen Wert zurückgesetzt werden. | ||
+ | - Herausforderung (freiwillig): | ||
+ | |||
+ |
api/projects/pong/start.txt · Zuletzt geändert: 2021/12/29 11:29 von 127.0.0.1