Nebenläufigkeit im Spiel
Nur Leistungskurs. Diese Seite gehört zum Kapitel Nebenläufigkeit, das zu den zusätzlichen Anforderungen des Leistungskurses gehört.
Dein Spiel ist schon lange nebenläufig. Der Spieler läuft, die Schleime kriechen, die Münzen drehen sich, die Wache entscheidet sich, alles scheinbar gleichzeitig. Die Bibliothek ruft dafür das run() jeder Figur reihum auf, etwa 60-mal in der Sekunde. Weil immer nur eins davon gleichzeitig läuft, geraten sie sich nie ins Gehege.
Die Leitfrage für dein Spiel: Gibt es etwas, das so lange dauert, dass das Spiel währenddessen stehen bleiben würde? Und welche Daten würden sich dann zwei Abläufe teilen?
Die MVPs sind kleine, eigenständig lauffähige Beispiele. Starte ein Beispiel mit ▶ und klicke für die Tastensteuerung in seine Ausgabe. Im Reiter Beispiel.java steht die jeweilige Idee. Falls ein Reiter Baukasten.java dabei ist, enthält er vorbereitete Hilfen für Figuren, Texte und Steuerung. Probiere zuerst die angegebene Änderung aus und übertrage dann die Idee in deine Werkstatt.
Mechaniken
Such dir höchstens eine aus. Hier geht es mehr um das Verstehen als um das Bauen.
Wer ist eigentlich zuerst dran?
Im Spiel: Ein Gegner und der Spieler berühren sich im selben Bild. Wird der Treffer einmal gezählt oder zweimal?
Dahinter steckt: Sowohl der Spieler als auch ein Gegner könnten den Treffer melden. Weil die Bibliothek die run()-Methoden nacheinander aufruft, gibt es eine feste Reihenfolge, aber du kennst sie nicht. Untersuche, ob dein Spiel in beiden Reihenfolgen dasselbe tut. Diese Frage ist der Kern jeder nebenläufigen Programmierung, auch wenn hier noch kein zweiter Thread im Spiel ist.
Aufwand: ★☆☆
MVP zum Ausprobieren: Vergleiche die beiden simulierten Aufrufreihenfolgen. Entferne dann die Sperre im Trefferregler.
In dein Spiel übertragen: Sammle Treffer an einer zentralen Stelle und begrenze sie auf einen je Bild oder je Schutzzeit.
Ein Level im Hintergrund erzeugen
Im Spiel: Ein großes Labyrinth oder ein Dungeon aus geteilten Räumen wird erzeugt, während schon ein Ladebild mit einer drehenden Münze läuft.
Dahinter steckt: ein eigener Thread, der das Level berechnet. Das Spiel fragt in run(), ob er fertig ist, und baut erst dann die Welt auf. Die beiden teilen sich das Ergebnis. Was passiert, wenn das Spiel es liest, während der Thread noch schreibt?
Aufwand: ★★★
MVP zum Ausprobieren: Die Münze dreht sich, während ein Thread den Plan berechnet. Erst der fertige Plan wird angezeigt.
In dein Spiel übertragen: Berechne außerhalb der Bühne in lokalen Daten und veröffentliche das fertige Ergebnis über eine geschützte Übergabe.
Ein Gegner, der nachdenkt
Im Spiel: Ein schlauer Gegner rechnet einen weiten Weg zum Spieler aus. Das dauert, aber das Spiel soll dabei nicht ruckeln.
Dahinter steckt: Die Wegsuche läuft in einem eigenen Thread, der Gegner bewegt sich bis dahin nach seinem alten Plan. Ist der neue Weg fertig, übernimmt er ihn. Überlege, an welcher Stelle sich die beiden Abläufe abstimmen müssen.
Aufwand: ★★★
MVP zum Ausprobieren: Die Kiste bleibt in Bewegung, während ein Thread einen Weg zum Münzziel sucht. Danach folgt sie dem Ergebnis.
In dein Spiel übertragen: Übergib der Wegsuche einen festen Schnappschuss. Übernimm den fertigen Weg im nächsten Bild und starte bei Bedarf eine neue Suche.
Und ohne Spiel?
| Im Spiel | Dieselbe Frage woanders |
|---|---|
alle run()-Methoden reihum |
ein Webserver, der viele Anfragen abwechselnd bedient |
| Level im Hintergrund erzeugen | eine App, die beim Laden einer Seite nicht einfriert |
| Spieler und Gegner melden denselben Treffer | zwei Kassen buchen dasselbe Konto |
Fürs Tagebuch: Beschreibe eine Stelle in deinem Spiel, an der zwei Abläufe dieselben Daten benutzen. Was könnte schiefgehen, wenn sie wirklich gleichzeitig liefen, und warum passiert es in deinem Spiel trotzdem nicht?
Weiterbauen kannst du in deiner Werkstatt.