SCHRITT 1 VON 5
SCHRITT 1 · Nur fliegen ist schöner ;-)

Dein erstes eigenes Programm

Du startest mit dem Minimal-Gerüst aus dem Tutorial und machst es zu deinem. Eigene Tastenbelegung, eigenes HUD, eigene Ausgabe nach dem Spiel.

⬡ ERGEBNIS: Der Standard-Lander fliegt mit deiner Steuerung
Wichtig — Dateiname und Name: Deine Datei heißt schritt_01.py und liegt in einem Ordner schritt_01/ (nicht lunarlander.py — das ist die API!). Die erste Zeile deines Programms enthält deinen Namen als Kommentar: # Name: [Vorname Nachname]
Tipp: Die API gibt beim Start automatisch eine Versionsmeldung aus. Wenn du weißt wie du sie abschaltest, darfst du das gerne tun — schau in die API-Dokumentation 😉
STARTPUNKT · schritt_1.py Fülle alle TODO-Stellen aus
# Name: [Vorname Nachname]          ← deinen echten Namen eintragen!
from lunarlander import *

# ════════════════════════════════════════════════════════════
# DEFINITIONSBEREICH
# ════════════════════════════════════════════════════════════

# ── Steuerung (Hook) ────────────────────────────────────────────────────
def myHandleKey(keyCode):
    # TODO: Wähle deine Tasten. Beispiele:
    # Pfeiltasten: hoch=38, links=37, rechts=39
    # WASD:        W=87,    A=65,     D=68
    pass


# ════════════════════════════════════════════════════════════
# SPIELEINSTELLUNGEN
# ════════════════════════════════════════════════════════════

# ── HUD ───────────────────────────────────────────────────────────────────
# erlaubt: "fuel", "vSpeed", "hSpeed", "height", "x",
#          "gravity", "rotation", "scale", "paused", "frameTime"
setHudItems(["fuel", "vSpeed", "height"])   # TODO: nach Wunsch anpassen


# ════════════════════════════════════════════════════════════
# SPIELSTART
# ════════════════════════════════════════════════════════════

init(myHandleKey)
print("Mein LunarLander — viel Erfolg!")   # TODO: eigene Startmeldung
start()


# ════════════════════════════════════════════════════════════
# AUSWERTUNG  (läuft erst nach Spielende)
# ════════════════════════════════════════════════════════════

# TODO: Gib aus ob du gelandet oder abgestürzt bist.
# TODO: Gib aus wie viel Treibstoff du verbraucht hast.
#        Tipp: Es gibt eine API-Funktion die den aktuellen Treibstoff liefert.

Wenn dein Programm läuft, erweitere es:

  • Füge setFuel(150) vor init() ein — wird es schwieriger? Welchen Wert liefert getFuel() nach dem Spielende?
  • Probiere setGravity(0.08) — was ändert sich am Flugverhalten?
  • Gib nach dem Spielende auch die Horizontalgeschwindigkeit aus — welche API-Funktion brauchst du dafür?

Am Ende von Schritt 1 hast du:

  • Eine funktionierende Steuerung mit selbst gewählten Tasten
  • Ein HUD mit mindestens 3 sinnvollen Werten
  • Eine Ausgabe nach Spielende: Ergebnis (gelandet/abgestürzt) + verbleibender Treibstoff
  • Deine Datei schritt_01.py mit deinem Namen in Zeile 1
SCHRITT 2 · EIGENER LANDER

setCustomDrawer() — Hook

Der gelbe Standard-Lander verschwindet. Du zeichnest deinen eigenen — mit eigenem Design, eigener Farbe, eigenem Charakter.

⬡ ERGEBNIS: Dein Lander fliegt mit deinem Design
📁 ARBEITSORGANISATION — VERSIONIERUNG

Bevor du anfängst: kopiere deinen schritt_01-Ordner, benenne die Kopie in schritt_02 um und arbeite ab jetzt nur in diesem neuen Ordner weiter.

So hast du immer eine funktionierende Version des vorherigen Schritts — falls etwas schiefgeht, kannst du zurück. Diese Methode nutzt du für jeden weiteren Schritt.

Dein Ordner-Schema: schritt_01/schritt_02/schritt_03/ → …

Erst skizzieren, dann coden

Zeichne deinen Lander auf Papier, bevor du Code schreibst. Trage Koordinaten ein: der Mittelpunkt ist (0, 0). Positive Y-Werte sind oben, negative unten.

Pflichtbestandteile:

  • Ein erkennbarer Rumpf (Rechteck, Kapsel, Polygon …)
  • Eine erkennbare Landebasis (Beine, Stützen, Kufen …)
  • Ein individuelles Merkmal — Cockpit, Antenne, Flagge, Aufschrift …
  • Mindestens zwei Farben
Zeichenbefehle
BefehlWirkung
penUp() / penDown()Stift heben / setzen
setPos(x, y)Teleportieren — nie Linie
moveTo(x, y)Linie zeichnen wenn penDown
setPenColor(f)Farbe als String
setPenWidth(b)Stiftbreite
dot(d)Ausgefüllter Kreis

Empfehlung: Im Custom Drawer mit Koordinaten zeichnen — setPos() und moveTo() mit (x,y)-Angaben sind am einfachsten zu lesen und zu debuggen. forward() und setHeading() funktionieren ebenfalls, erfordern aber etwas mehr Vorstellungsvermögen.

Koordinaten-System
+x +y (0,0) setPos(-14,8)
STARTPUNKT · schritt_2.py Ersetze meinLander() durch dein Design
from lunarlander import *

# ════════════════════════════════════════════════════════════
# DEFINITIONSBEREICH
# ════════════════════════════════════════════════════════════

# ── Eigener Lander (Hook) ───────────────────────────────────────────────
def meinLander():
    # TODO: Dein Design — nur setPos() und moveTo() für Linien verwenden!
    # Mindestens: Rumpf, Beine, 1 Merkmal, 2 Farben
    pass

# ── Steuerung (Hook) ────────────────────────────────────────────────────
def myHandleKey(keyCode):
    pass   # TODO: deine Tastenbelegung aus Schritt 1


# ════════════════════════════════════════════════════════════
# SPIELEINSTELLUNGEN
# ════════════════════════════════════════════════════════════

# ── Lander ────────────────────────────────────────────────────────────────
# TODO: CollisionProbe anpassen wenn nötig (south = tiefster Punkt deines Landers)
# setCollisionProbe(0, 0, 24, 0)

# ── HUD ───────────────────────────────────────────────────────────────────
setHudItems(["fuel", "vSpeed", "height"])


# ════════════════════════════════════════════════════════════
# HOOKS ANMELDEN
# ════════════════════════════════════════════════════════════

setCustomDrawer(meinLander)


# ════════════════════════════════════════════════════════════
# SPIELSTART
# ════════════════════════════════════════════════════════════

init(myHandleKey)
start()


# ════════════════════════════════════════════════════════════
# AUSWERTUNG
# ════════════════════════════════════════════════════════════

if hasLanded():
    print("Gelandet! Treibstoff:", getFuel())
elif hasCrashed():
    print("Absturz!")

setPos() teleportiert immer ohne Linie — auch bei penDown(). Für Linien immer moveTo() verwenden — nicht forward(). Zum Debuggen: setShowCollisionProbe(True) zeigt den Kollisionspunkt als roten Punkt.

Am Ende von Schritt 2 hast du:

  • Einen Lander mit Rumpf, Landebasis und individuellem Merkmal
  • Mindestens zwei verschiedene Farben
  • Eine korrekt gesetzte CollisionProbe (sichtbar mit setShowCollisionProbe(True) überprüft)
SCHRITT 3 · EIGENE WELT

Terrain, Landezone, Schwerkraft

Dein Lander braucht eine Welt. Du gestaltest das Gelände, legst fest wo gelandet werden darf — und entscheidest wie viel Schwerkraft herrscht.

⬡ ERGEBNIS: Dein Lander in deiner eigenen Welt
Terrain-Design

Das Terrain ist eine Liste von Höhenwerten — von links nach rechts gelesen. Mindestens 8 Werte. Größere Zahlen = höheres Gelände.

Die Landezonen werden als Index-Bereich angegeben — Index 0 ist ganz links. Flache Bereiche im Terrain eignen sich als Landeplatz.

FunktionWirkungStandard
setTerrain([...])Geländeprofil setzen[30,60,90,70,20,20,20,20,55,100,120,80,40]
setLandingZone(start, ende)Einen LandeplatzIndizes 4–7 ← die gelben Werte oben
setLandingZones([(startIndex1, endIndex1), (startIndex2, endIndex2)])Mehrere Landeplätze
setGravity(wert)Schwerkraft0.15
setFuel(menge)Starttreibstoff200

Die gelb markierten Werte in der Terrain-Liste (Index 4–7) bilden den flachen Bereich — das ist die Landezone.

STARTPUNKT · schritt_3.py Gestalte Terrain, Landezone und Schwerkraft
from lunarlander import *

# ════════════════════════════════════════════════════════════
# DEFINITIONSBEREICH
# ════════════════════════════════════════════════════════════

# ── Eigener Lander (Hook) ───────────────────────────────────────────────
def meinLander():
    pass   # TODO: dein Design aus Schritt 2

# ── Steuerung (Hook) ────────────────────────────────────────────────────
def myHandleKey(keyCode):
    pass   # TODO: deine Tastenbelegung


# ════════════════════════════════════════════════════════════
# SPIELEINSTELLUNGEN
# ════════════════════════════════════════════════════════════

# ── Lander ────────────────────────────────────────────────────────────────
# setCollisionProbe(0, 0, 24, 0)   # TODO: aus Schritt 2 übernehmen

# ── Welt ──────────────────────────────────────────────────────────────────
# TODO: Gestalte dein Terrain. Flache Bereiche = mögliche Landeplätze.
setTerrain([30, 80, 40, 10, 10, 10, 60, 90, 50, 20])   # TODO: eigenes Terrain

# TODO: Setze deinen Landeplatz (Index des flachen Bereichs)
setLandingZone(3, 5)

# TODO: Wähle eine Schwerkraft (0.05 = leicht, 0.25 = schwer)
setGravity(0.15)

# TODO: Wie viel Treibstoff bekommt der Spieler?
setFuel(200)

# ── HUD ───────────────────────────────────────────────────────────────────
setHudItems(["fuel", "vSpeed", "height", "gravity"])


# ════════════════════════════════════════════════════════════
# HOOKS ANMELDEN
# ════════════════════════════════════════════════════════════

setCustomDrawer(meinLander)


# ════════════════════════════════════════════════════════════
# SPIELSTART
# ════════════════════════════════════════════════════════════

init(myHandleKey)
start()


# ════════════════════════════════════════════════════════════
# AUSWERTUNG
# ════════════════════════════════════════════════════════════

if hasLanded():
    print("Gelandet! Treibstoff:", getFuel())
elif hasCrashed():
    print("Absturz!")

Füge am Ende deiner schritt_03.py diese Kommentare ein und beantworte sie:

IN SCHRITT_03.PY EINFÜGEN
# ════════════════════════════════════════════════════════════
# WELT-BESCHREIBUNG
# ════════════════════════════════════════════════════════════
# Thema meiner Welt (Mond, Mars, Asteroid, …):
#   [deine Antwort]
#
# Begründung meiner Schwerkraft (gewählt: ___):
#   [warum genau dieser Wert?]
#
# Schwierigkeitsgrad — und ist das so gewollt?
#   [deine Antwort]

Mehrere Landeplätze mit setLandingZones([[3,5],[8,10]]). Der erste Landeplatz kann leichter sein (breiter, flacher), ein zweiter schwieriger (schmal, schwer zugänglich).

Am Ende von Schritt 3 hast du:

  • Ein eigenes Terrain mit mindestens einem sinnvoll platzierten Landeplatz
  • Eine Schwerkraft die zur Welt passt
  • Die drei Welt-Kommentare am Ende der schritt_03.py ausgefüllt
  • Alles gespeichert im Ordner schritt_03/
SCHRITT 4 · SPIELLOGIK

setUpdateFunction() — Hook

Das Spiel bekommt eine Stimme. Warnungen, Hinweise, ein einfaches Punktesystem — alles läuft in deiner Update-Funktion, die jeden Frame aufgerufen wird.

⬡ ERGEBNIS: Dein Spiel gibt Feedback während des Flugs
Die global-Regel

Variablen die du in einer Funktion veränderst, müssen mit global deklariert werden. Nur lesen geht ohne global.

Eigene Hilfsfunktionen kannst du einfach per Name aufrufen — auch aus Hooks heraus. Die global-Regel gilt dort genauso.

STARTPUNKT · schritt_4.py Füge mindestens 2 Warnungen und ein Punktesystem ein
from lunarlander import *

# ════════════════════════════════════════════════════════════
# DEFINITIONSBEREICH
# ════════════════════════════════════════════════════════════

# ── Spielzustand (globale Variablen) ─────────────────────────────────────
punkte             = 1000
warnungTreibstoff  = False
warnungSpeed       = False

# ── Hilfsfunktionen ──────────────────────────────────────────────────────
def zeigeWarnung(text):
    print("*** WARNUNG:", text, "***")

# ── Eigener Lander (Hook) ───────────────────────────────────────────────
def meinLander():
    pass   # TODO: dein Design

# ── Update-Logik (Hook) ─────────────────────────────────────────────────
def meinUpdate():
    global punkte, warnungTreibstoff, warnungSpeed

    punkte = punkte - 1   # Zeitdruck: 1 Punkt pro Frame abziehen

    # TODO: Warnung 1 — einmalig wenn Treibstoff unter 50 sinkt
    # Nutze zeigeWarnung() und warnungTreibstoff als Merker

    # TODO: Warnung 2 — einmalig wenn Höhe unter 60 und vSpeed über 3.5

    # TODO (Bonus): Hinweis wenn isOverLandingZone() — aber nur alle 30 Frames

# ── Steuerung (Hook) ────────────────────────────────────────────────────
def myHandleKey(keyCode):
    pass   # TODO: deine Tastenbelegung


# ════════════════════════════════════════════════════════════
# SPIELEINSTELLUNGEN
# ════════════════════════════════════════════════════════════

# ── Lander ────────────────────────────────────────────────────────────────
# setCollisionProbe(0, 0, 24, 0)   # TODO: aus Schritt 2 übernehmen

# ── Welt ──────────────────────────────────────────────────────────────────
# TODO: setTerrain, setLandingZone, setGravity, setFuel aus Schritt 3 einfügen

# ── HUD ───────────────────────────────────────────────────────────────────
setHudItems(["fuel", "vSpeed", "height"])


# ════════════════════════════════════════════════════════════
# HOOKS ANMELDEN
# ════════════════════════════════════════════════════════════

setCustomDrawer(meinLander)
setUpdateFunction(meinUpdate)


# ════════════════════════════════════════════════════════════
# SPIELSTART
# ════════════════════════════════════════════════════════════

init(myHandleKey)
start()


# ════════════════════════════════════════════════════════════
# AUSWERTUNG
# ════════════════════════════════════════════════════════════

if hasLanded():
    bonus  = getFuel() * 2
    punkte = punkte + bonus
    print("GELANDET! Punkte:", punkte, "| Treibstoffbonus:", bonus)
elif hasCrashed():
    print("ABSTURZ. Punkte:", punkte)

Erweitere deine Update-Funktion:

  • Eine dritte Warnung nach eigener Idee
  • Baue eine Pause-Taste in deinen handleKey ein (togglePause())
  • Bonus: Schreibe eine eigene Hilfsfunktion berechnePunkte() die die Punkteberechnung kapselt — und rufe sie aus dem Update auf

Am Ende von Schritt 4 hast du:

  • Mindestens 2 verschiedene Warnmeldungen (einmalig, nicht jeden Frame)
  • Ein Punktesystem das während des Spiels läuft
  • Mindestens eine eigene Hilfsfunktion die aus dem Update aufgerufen wird
SCHRITT 5 · AUSWERTUNG & FEINSCHLIFF

Das fertige Spiel

Alles zusammenführen, aufräumen, fertigstellen. Eine gute Startmeldung, eine vollständige Auswertung, ein Spiel das sich rund anfühlt.

⬡ ERGEBNIS: Ein vollständiges, spielbares Spiel
Checkliste — was gehört in ein fertiges Spiel?

Klicke die Punkte an wenn du sie erledigt hast — der Browser merkt sich deinen Stand.

ABGABE-VORLAGE · mein_lander.py Zusammenführung aller Schritte
from lunarlander import *

# ════════════════════════════════════════════════════════════
# Mein LunarLander
# Name:   [dein Name]
# Klasse: WPF Informatik
# ════════════════════════════════════════════════════════════


# ════════════════════════════════════════════════════════════
# DEFINITIONSBEREICH
# ════════════════════════════════════════════════════════════

# ── Spielzustand (globale Variablen) ──────────────────────────────────────
punkte = 1000
# TODO: weitere Variablen (Warnungsmerker etc.)

# ── Hilfsfunktionen ───────────────────────────────────────────────────────
# TODO: deine Hilfsfunktionen hier

# ── Eigener Lander (Hook) ───────────────────────────────────────────────
def meinLander():
    pass   # TODO: dein fertiges Design

# ── Update-Logik (Hook) ─────────────────────────────────────────────────
def meinUpdate():
    global punkte
    # TODO: Warnungen, Punktelogik, Hinweise

# ── Steuerung (Hook) ────────────────────────────────────────────────────
def myHandleKey(keyCode):
    pass   # TODO: deine Tastenbelegung


# ════════════════════════════════════════════════════════════
# SPIELEINSTELLUNGEN
# ════════════════════════════════════════════════════════════

# ── Lander ────────────────────────────────────────────────────────────────
# setCollisionProbe(0, 0, 24, 0)   # TODO: anpassen

# ── Welt ──────────────────────────────────────────────────────────────────
# TODO: setTerrain([...])
# TODO: setLandingZone(start, ende)
# TODO: setGravity(wert)
# TODO: setFuel(menge)

# ── HUD ───────────────────────────────────────────────────────────────────
setHudItems(["fuel", "vSpeed", "height"])   # TODO: anpassen


# ════════════════════════════════════════════════════════════
# HOOKS ANMELDEN
# ════════════════════════════════════════════════════════════

setCustomDrawer(meinLander)
setUpdateFunction(meinUpdate)


# ════════════════════════════════════════════════════════════
# SPIELSTART
# ════════════════════════════════════════════════════════════

init(myHandleKey)
print("=" * 40)
print("[dein Titel]")
print("Steuerung: [deine Tasten]")
print("Ziel: Weich auf der markierten Zone landen.")
print("=" * 40)
start()


# ════════════════════════════════════════════════════════════
# AUSWERTUNG
# ════════════════════════════════════════════════════════════

print("=" * 40)
if hasLanded():
    bonus  = getFuel() * 2
    punkte = punkte + bonus
    print("SOFT LANDING!")
    print("Punkte:", punkte, "| Treibstoffbonus:", bonus)
elif hasCrashed():
    print("ABSTURZ!")
    print("Endpunkte:", punkte)
print("=" * 40)

Testphase — Ein Programm gilt erst dann als fertig wenn es getestet wurde.

Arbeite diese Test-Checkliste durch:

  • Normalstart: Programm frisch starten — erscheint die Startmeldung vollständig und korrekt?
  • Erfolgreiche Landung: Weich auf der Landezone aufsetzen — stimmt die Auswertung (Punkte, Treibstoff)?
  • Absturz: Absichtlich zu schnell aufprallen — kommt die Absturz-Meldung?
  • Kein Treibstoff: Solange Gas geben bis der Tank leer ist — was passiert?
  • Falsche Zone: Außerhalb der Landezone landen — wird das als Absturz gewertet?
  • Benutzersicht: Stell dir vor, du startest dein Programm zum ersten Mal — ist alles sofort verständlich? Kannst du es ohne Erklärung spielen?

Bonus: Entwickle ein eigenes Testszenario das einen möglichen Fehler in deiner Spiellogik aufdecken könnte — und dokumentiere es als Kommentar in deiner Datei.

Abgabe: Speichere deine fertige Datei als schritt_05.py im Ordner schritt_05/. Die Datei muss lauffähig sein und deinen Namen in der ersten Zeile tragen.