Lektion 3 von 4Spiele programmieren
Spiele programmieren · Lektion 3 · 60 Minuten
Projekt: Schlangenspiel
Das lernst du
- Ein Spielfeld aus Kästchen mit
spiel.raster()undspiel.feld()bauen - Eine Schlange als Liste von Positionen speichern und wachsen lassen
- Mit
spiel.gedrueckt()die Richtung wechseln und das Spielende erkennen
Eine Schlange aus Kästchen
Beim Schlangenspiel kriecht eine Schlange über ein Spielfeld aus Kästchen. Frisst sie Futter, wird sie länger. Stößt sie an die Wand oder an sich selbst, ist das Spiel vorbei. Das ist ein Klassiker – und du baust ihn jetzt nach.
Das Raster
spiel.raster(20, 15, 20) macht ein Spielfeld aus 20 Spalten und 15 Zeilen. Jedes Kästchen ist 20 Pixel groß. Mit spiel.feld(spalte, zeile, farbe) füllst du ein Kästchen. Gezählt wird ab 0:
from codelix import spiel
spiel.raster(20, 15, 20)
spiel.feld(0, 0, "white") # oben links
spiel.feld(19, 14, "white") # unten rechts
spiel.feld(10, 7, "red") # ungefähr in der Mitte
print("Spalten:", spiel.spalten(), "Zeilen:", spiel.zeilen())Die Schlange ist eine Liste
Jedes Stück der Schlange ist eine Position [spalte, zeile]. Die ganze Schlange ist eine Liste davon. Das erste Element ist der Kopf:
from codelix import spiel
spiel.raster(20, 15, 20)
schlange = [[5, 7], [4, 7], [3, 7]]
for stueck in schlange:
spiel.feld(stueck[0], stueck[1], "lime")
print("Kopf:", schlange[0])
print("Länge:", len(schlange))So kriecht eine Schlange
Der Trick: Du schiebst nicht jedes Stück einzeln weiter. Du setzt vorne einen neuen Kopf ein und nimmst hinten ein Stück weg. Die Mitte bleibt, wie sie ist:
schlange = [[5, 7], [4, 7], [3, 7]]
print("vorher: ", schlange)
spalte, zeile = schlange[0]
schlange.insert(0, [spalte + 1, zeile]) # neuer Kopf rechts daneben
schlange.pop() # letztes Stück weg
print("nachher:", schlange)Und wenn die Schlange frisst? Dann lässt du pop() einfach weg. Schon ist sie ein Stück länger.
Richtung wechseln
Die Schlange soll nicht in jedem Bild ein Feld weiterspringen – das wäre viel zu schnell. Mit spiel.bildnummer() % 6 == 0 bewegt sie sich nur in jedem sechsten Bild.
Für die Richtung nimmst du spiel.gedrueckt(). Es ist nur in dem Bild True, nachdem du die Taste gedrückt hast. So geht auch ein ganz kurzer Tipper nicht verloren:
from codelix import spiel
spiel.raster(20, 15, 20)
kopf = [10, 7]
stand = {"richtung": "rechts"}
def schritt():
for taste in ["links", "rechts", "oben", "unten"]:
if spiel.gedrueckt(taste):
stand["richtung"] = taste
if spiel.bildnummer() % 6 == 0:
if stand["richtung"] == "rechts":
kopf[0] = (kopf[0] + 1) % 20
elif stand["richtung"] == "links":
kopf[0] = (kopf[0] - 1) % 20
elif stand["richtung"] == "oben":
kopf[1] = (kopf[1] - 1) % 15
else:
kopf[1] = (kopf[1] + 1) % 15
spiel.feld(kopf[0], kopf[1], "lime")
spiel.text(8, 6, stand["richtung"], "white", 16)
spiel.starten(schritt)Siehst du das % 20? Damit kommt der Kopf auf der anderen Seite wieder herein. Im echten Spiel ist die Wand dagegen tödlich.
Weiterbauen: Wenn deine Aufgabe klappt: Verhindere, dass die Schlange direkt umdrehen kann (von rechts sofort nach links). Lass sie mit jedem Punkt schneller werden – zum Beispiel mit
% 5statt% 6. Und achte darauf, dass das Futter nicht auf der Schlange erscheint.
Deine Aufgabe
Jetzt bist du dran
Das Spiel ist fast fertig – es fehlen die zwei wichtigsten Funktionen. 1. bewegen(schlange, richtung, frisst): Setz vorne einen neuen Kopf ein, ein Feld weiter in richtung ("rechts", "links", "oben" oder "unten"). Frisst die Schlange gerade nicht, nimm hinten das letzte Stück weg. 2. ist_vorbei(schlange, spalten, zeilen): Gib True zurück, wenn der Kopf außerhalb des Spielfelds liegt oder auf einem anderen Teil der Schlange. Sonst False.
import random
from codelix import spiel
spiel.raster(20, 15, 20)
schlange = [[5, 7], [4, 7], [3, 7]]
stand = {"richtung": "rechts", "futter": [12, 7], "punkte": 0}
def bewegen(schlange, richtung, frisst):
pass
def ist_vorbei(schlange, spalten, zeilen):
return False
def schritt():
for taste in ["links", "rechts", "oben", "unten"]:
if spiel.gedrueckt(taste):
stand["richtung"] = taste
if spiel.bildnummer() % 6 == 0:
spalte, zeile = schlange[0]
ziel = {"rechts": [spalte + 1, zeile], "links": [spalte - 1, zeile],
"oben": [spalte, zeile - 1], "unten": [spalte, zeile + 1]}[stand["richtung"]]
frisst = ziel == stand["futter"]
bewegen(schlange, stand["richtung"], frisst)
if frisst:
stand["punkte"] = stand["punkte"] + 1
stand["futter"] = [random.randint(0, 19), random.randint(0, 14)]
if ist_vorbei(schlange, spiel.spalten(), spiel.zeilen()):
spiel.text(110, 130, "Spiel vorbei!", "tomato", 30)
spiel.ende()
spiel.feld(stand["futter"][0], stand["futter"][1], "red")
for stueck in schlange:
spiel.feld(stueck[0], stueck[1], "lime")
spiel.text(8, 6, f"Punkte: {stand['punkte']}", "white", 16)
spiel.starten(schritt)- Denkanstoß
Hol dir mit spalte, zeile
=schlange[0]den Kopf. Füg mitschlange.insert(0, [spalte + 1, zeile])vorne an und nimm mitschlange.pop()hinten weg. - Welcher Befehl hilft?
Oben heißt Zeile − 1 (y zeigt nach unten!), unten heißt Zeile
+1.Nimm das letzte Stück nur weg, wenn frisst
Falseist –ifnotfrisst:schlange.pop()Gültig sind Spalten von 0 bis spalten − 1. Prüfe also: spalte
<0orspalte>=spalten – genauso für die Zeile.schlange[1:]ist die Schlange ohne Kopf. Mitschlange[0]inschlange[1:]prüfst du, ob der Kopf dort vorkommt. - Lückencode – ergänze die ___
import random from codelix import spiel spiel.raster(20, 15, 20) schlange = [[5, 7], [4, 7], [3, 7]] stand = {"richtung": "rechts", "futter": [12, 7], "punkte": 0} def bewegen(schlange, richtung, frisst): spalte, zeile = schlange[0] if ___: spalte = ___ elif ___: spalte = ___ elif ___: zeile = ___ elif ___: zeile = ___ schlange.insert(___) if ___: schlange.pop() def ist_vorbei(schlange, spalten, zeilen): spalte, zeile = schlange[0] if ___: return ___ return ___ def schritt(): for taste in ["links", "rechts", "oben", "unten"]: if spiel.gedrueckt(taste): stand["richtung"] = taste if spiel.bildnummer() % 6 == 0: spalte, zeile = schlange[0] ziel = {"rechts": [spalte + 1, zeile], "links": [spalte - 1, zeile], "oben": [spalte, zeile - 1], "unten": [spalte, zeile + 1]}[stand["richtung"]] frisst = ziel == stand["futter"] bewegen(schlange, stand["richtung"], frisst) if frisst: stand["punkte"] = stand["punkte"] + 1 stand["futter"] = [random.randint(0, 19), random.randint(0, 14)] if ist_vorbei(schlange, spiel.spalten(), spiel.zeilen()): spiel.text(110, 130, "Spiel vorbei!", "tomato", 30) spiel.ende() spiel.feld(stand["futter"][0], stand["futter"][1], "red") for stueck in schlange: spiel.feld(stueck[0], stueck[1], "lime") spiel.text(8, 6, f"Punkte: {stand['punkte']}", "white", 16) spiel.starten(schritt)
Ohne Hinweise gelöst gibt es einen ⭐ auf deiner Fortschrittsseite.
Lösung anzeigen🔒 Erst nach allen Hinweisen oder 2 Prüf-Versuchen
Versuch es erst selbst – aus Fehlern lernt man am meisten. Hier ist eine mögliche Lösung:
import random
from codelix import spiel
spiel.raster(20, 15, 20)
schlange = [[5, 7], [4, 7], [3, 7]]
stand = {"richtung": "rechts", "futter": [12, 7], "punkte": 0}
def bewegen(schlange, richtung, frisst):
spalte, zeile = schlange[0]
if richtung == "rechts":
spalte = spalte + 1
elif richtung == "links":
spalte = spalte - 1
elif richtung == "oben":
zeile = zeile - 1
elif richtung == "unten":
zeile = zeile + 1
schlange.insert(0, [spalte, zeile])
if not frisst:
schlange.pop()
def ist_vorbei(schlange, spalten, zeilen):
spalte, zeile = schlange[0]
if spalte < 0 or spalte >= spalten or zeile < 0 or zeile >= zeilen:
return True
return schlange[0] in schlange[1:]
def schritt():
for taste in ["links", "rechts", "oben", "unten"]:
if spiel.gedrueckt(taste):
stand["richtung"] = taste
if spiel.bildnummer() % 6 == 0:
spalte, zeile = schlange[0]
ziel = {"rechts": [spalte + 1, zeile], "links": [spalte - 1, zeile],
"oben": [spalte, zeile - 1], "unten": [spalte, zeile + 1]}[stand["richtung"]]
frisst = ziel == stand["futter"]
bewegen(schlange, stand["richtung"], frisst)
if frisst:
stand["punkte"] = stand["punkte"] + 1
stand["futter"] = [random.randint(0, 19), random.randint(0, 14)]
if ist_vorbei(schlange, spiel.spalten(), spiel.zeilen()):
spiel.text(110, 130, "Spiel vorbei!", "tomato", 30)
spiel.ende()
spiel.feld(stand["futter"][0], stand["futter"][1], "red")
for stueck in schlange:
spiel.feld(stueck[0], stueck[1], "lime")
spiel.text(8, 6, f"Punkte: {stand['punkte']}", "white", 16)
spiel.starten(schritt)