lehrkraefte:snr:informatik:glf22:python:snake

Online programmieren über dieses trinket… funktioniert nicht sinnvoll: Tastendrücke werden nicht (oder sehr spät) erkannt, f-strings klappen nicht (was nicht so schlimm wäre), Grösse des Spielfeldes muss man anpassen, damit alles angezeigt wird. Letzteres Problem auch bei manch kleinem Laptop-Bildschirm.

Pygame: a ball game and snake

Pygame ist eine Python-Library zur Spiele-Programmierung.

Ziele dieses Abschnitts:

  • einen groben Eindruck bekommen, wie ein Snake-Programm in Python funktioniert.

Selbst solch ein Programm zu schreiben ist deutlich schwieriger und braucht vor allem viel Übung im Programmieren.

Hist ist ein Link zu einem in pygame programmierten Spiel (bitte nur kurz ausprobieren).

Falls das Programm bei dir nicht läuft:

Falls das Programm bei dir nicht läuft:

Es könnte sein, dass pygame nicht installiert ist: Installation mit pip install pygame in der “command line”/“cmd”/Eingabeaufforderung/Befehlszeile.

Alternativ kannst du online programmieren:

Lösche das Programm dort und ersetze es durch das Programm “ball-game.py”.

Die Tastatursteuerung ist online wohl etwas langsam.


Der Spieler (grünes Quadrat) gewinnt ein Leben, wenn er den purpurfarbenen Ball fängt, und verliert zwei Leben, wenn der Ball an der rechten Seite des Spielfeldrandes reflektiert wird. Man startet am Anfang mit 10 Leben, gewinnt bei 20 Leben und verliert bei 0 Leben.

Das grüne Quadrat wird mit den Pfeiltasten gesteuert, jedoch hat der Programmierer dies nicht wie erwünscht hinbekommen. Auch bewegt sich der Ball nicht wie beabsichtigt.

Die gewünschte Steuerung mit den Pfeiltasten ist wie folgt.

  • Jedes Drücken einer Pfeiltaste bewegt das Quadrat um ein Feld in die entsprechende Richtung, mit folgenden Ausnahmen:
  • Das Quadrat kann das Spielfeld rechts und links nicht verlassen und stösst dort an die Ränder an.
  • Wenn es das Spielfeld oben verlässt, kommt es sofort an derselben x-Koordinate unten in das Spielfeld und umgekehrt.

Erwünschte Bewegung des Balls:

  • An allen Seiten des Spielfelds ausser der linken soll der Ball normal reflektiert werden.
  • An der linken Seite soll das bereits programmierte zufällige Verhalten bestehen bleiben.

Beachte: Für die folgenden Aufgaben musst du nur einen geringen Teil des Programms verstehen! Was du wissen musst, ist jeweils in den Hinweisen erläutert.

Teilaufgabe 1

Hilf dem Programmierer, die gewünschte Steuerung mit den Pfeiltasten zu erreichen (dabei sollst du den Ball vollständig ignorieren, es geht nur um das grüne Quadrat).

  • (1) Kümmere dich darum, dass jede der vier Pfeiltasten das Quadrat um genau ein Feld in die gewünschte Richtung bewegt.
  • (2) Kümmere dich darum, dass das Quadrat nicht aus dem Spielfeld verschwindet, sondern das oben beschriebene Verhalten zeigt.

Dafür musst du nur etwa 20 Zeilen ab Zeile 176 ändern, das gesamte restliche Programm bleibt unverändert (vgl. Kommentar in Zeile 173).

Hinweise

Hinweise

Die gesamte if-elif-…-Struktur kann unverändert bleiben.

Die y-Achse des “Spielfeld-Koordinatensystems” zeigt nach unten! Der Ursprung des Koordinatensystems ist in der linken oberen Ecke des Spielfeldes.

Die aktuelle Position des grünen Quadrats ist in der Variablen spieler gespeichert:

  • spieler.x ist seine $x$-Koordinate,
  • spieler.y ist seine $y$-Koordinate.

Überlege zuerst, wie du diese Koordinaten bei den jeweiligen Pfeiltasten verändern musst.

Für das gewünschte Verhalten an den Rändern des Spielfelds: Die Koordinaten des Spielfelds gehen in

  • $x$-Richtung von 0 bis MAXX und in
  • $y$-Richtung von 0 bis MAXY.

Teilaufgabe 2

Hilf dem Programmierer, das gewünschte Reflexionsverhalten des Balles zu erreichen.

Dafür musst du nur etwa 10 Zeilen ab Zeile 220 anpassen, das gesamte restliche Programm bleibt unverändert (vgl. Kommentar in Zeile 217 - Zeilenangaben beziehen sich auf das “Originalprogramm”).

Hinweis

Hinweis

Beobachte zuerst genau, an welchen der drei Spielfeldränder (oben, rechts, unten) das Reflexionsverhalten falsch ist.

Die if-Bedingungen können und sollen so stehen bleiben.

Die aktuelle Position des Balls ist in der Variablen ball gespeichert:

  • ball.x ist seine $x$-Koordinate,
  • ball.y ist seine $y$-Koordinate.

Während des Spielablaufs wird die sogenannte “game loop” (beginnend in Zeile 140 und endend in Zeile 236) immer wieder durchlaufen (ca. 40 Mal pro Sekunde). Die Variable bewegungsrichtung_ball hat ebenfalls zwei Komponenten:

  • bewegungsrichtung_ball.x ist seine x-Koordinate,
  • bewegungsrichtung_ball.y ist seine y-Koordinate.

In jedem Durchlauf der “game loop” wird (in Zeile 215) dieser Vektor zur Position ball des Balls hinzuaddiert ($x$-Koordinate zu $x$-Koordinate, $y$-Koordinate zu $y$-Koordinate, wie bei der Addition von Kräften in der Physik bzw. der Vektoraddition in der Mathematik). Deswegen wirkt die Bewegung des Balls kontinuierlich.

Passe nun jeweils die Zeilen nach den drei if-Zeilen an; zwei Programm-Zeilen können eingespart werden.

Teilaufgabe 3

Schau dir zuerst die “game loop” (Zeilen 140 bis 236) und dann das Hauptprogamm (beginnend in Zeile 120) an und versuche, möglichst viel zu verstehen. Wer will, kann sich natürlich auch den Rest des Programms anschauen.

Teilaufgabe 4

Viel Spass beim Spielen! Mit der nun einfacheren Bedienung hat man bessere Gewinnchancen! - Aber bitte nicht zu lange spielen.

Bonusaufgaben

(teilweise vielleicht auch eine gute Idee, diese in Zukunft einzubauen)

  • Steuere eine zweite farbige Box mit den Tasten a, s, d, w. Was passiert bei einer Kollision der beiden Spieler?
  • Ändere die Steuerung (vermutlich nicht so leicht; braucht u.a. KEYUP als mögliches key event):
    • Wenn man auf einer Pfeiltaste bleibt, bewegt sich das grüne Quadrat immer weiter in die entsprechende Richtung.
    • Das Quadrat bewegt sich kontinuierlich (ähnlich wie der Ball). Das Drücken einer Pfeiltaste ändert die Richtung. (Diese Art der Steuerung werden wir bei Snake verwenden.)

Um Snake zu programmieren, kommt man kaum um Listen herum, denn die Positionen, an denen sich die “Körperglieder” der Schlange befinden, speichert man sinnvollerweise in einer solchen Liste.

In gewisser Weise kommen wir hier an's Ende des Programmierkurses: Neben den Kontrollstrukturen (if-statements für Bedingungen, for- und while-Schleifen für Wiederholungen, Funktionen) sind beim Programmieren Datentypen und Datenstrukturen (wie Listen) essentiell. Wer das bisher erklärte kennt, kann mit etwas Übung eigentlich alles programmieren.

Statt auf den Abschnitt Listen des Programmierkurses über Listen zu verweisen, erkläre ich hier direkt, was für Snake nötig ist.

Das hier verborgene Programm enthält alles über Listen, was in Snake benötigt wird

Das hier verborgene Programm enthält alles über Listen, was in Snake benötigt wird

Per Python-Shell erklären oder direkt das Programm laufen lassen, am besten mit Breakpoint ganz am Anfang.

listen-demo.py
# Beispiel 1:
# Top 5 der Vornamen in der italienischen Schweiz 2021 laut BFS, https://babynames-stat.ch/de/index.html
namensliste = ['Leonardo', 'Alessandro', 'Liam', 'Noah', 'Tommaso']
print(namensliste)
print(namensliste[3])
print(namensliste[0])
namensliste[3] = 'Urs'
print(namensliste)
print("Liam" in namensliste)
print("Luca" in namensliste)
print(len(namensliste))
for name in namensliste:
    print('Mi chiamo ' + name + '.')
namensliste.insert(0, 'Nathan')
print(namensliste)
namensliste.insert(3, 'Ephraim')
print(namensliste)
namensliste.pop()
print(namensliste)
namensliste.pop(2)
print(namensliste)
print(namensliste[1:3])
 
# Beispiel 2:
notenliste=[1, 2, 3, 4, 5, 6, 5, 4, 3, 2, 1]
summe = 0
for note in notenliste:
    summe = summe + note
print(summe / len(notenliste))
 
# Beispiel 3:
from random import *
liste_der_wuerfe = []
while liste_der_wuerfe[0:2] != [0, 0]:
    liste_der_wuerfe.insert(0, randrange(2))
    print(liste_der_wuerfe)    

Ausserdem sollte man verstehen, warum eine Liste die naheliegende Datenstruktur für Snake ist (verbale Erklärung mit Snake-Beispielprogramm, anhalten mit Leertaste, Liste wird unten angezeigt).

Tafelfoto dazu

Tafelfoto dazu

Hist ist ein Link zu einem in pygame programmierten snake-ähnlichen Spiel.

(Zusammen die per ## GEMEINSAM ANSCHAUEN: markierten Stellen anschauen: An diesen Stellen wird eine Liste namens schlange verwendet, um die aktuellen Positionen der Schlangenquadrate zu speichern.)

Korrigiere dieses Programm, so dass es dem üblichen Snake ähnelt:

  • Statt mit den Tasten r, t, f, g soll die Steuerung wie gewohnt mit den Pfeiltasten funktionieren.
  • Wenn die Schlange einen Apfel frisst, soll die unter dem Spielfeld angezeigte Variable gefressene_aepfel um eins erhöht werden.
  • Pro gefressenem Apfel soll die Länge der Schlange um eins wachsen.
  • Wenn die Schlange gegen eine der vier Wände des Spielfelds läuft, endet das Spiel.
  • Färbe den Kopf der Schlange in einer anderen Farbe, damit man weiss, wo er ist.

Hinweis: Es sind nur wenige Änderungen innnerhalb der “game loop” (ab Zeile 171) nötig.

Für diejenigen, die Online programmieren (da dort f-strings wohl nicht funktionieren; hier sind noch diverse auskommentierte Sachen einzukommentieren - bitte mich fragen; erfahrungsgemäss ist die Tastatureingabe online so langsam, dass es keinen Spass macht.):

Für diejenigen, die Online programmieren (da dort f-strings wohl nicht funktionieren; hier sind noch diverse auskommentierte Sachen einzukommentieren - bitte mich fragen; erfahrungsgemäss ist die Tastatureingabe online so langsam, dass es keinen Spass macht.):

snake-zu-verbessern-fuer-online
import pygame
from pygame.locals import *
from random import *
 
# Geschwindigkeit des Spiels bzw. genauer
# Frequenz, mit der das Spielfeld neu gezeichnet wird.
FRAMES_PER_SECOND_AM_ANFANG = 7
VERGROESSERUNG_PRO_APFEL = 0.5
 
# Das Spielfeld besteht aus kleinen rechteckigen Boxen mit Koordinaten
# 0 bis MAXX (jeweils einschliesslich) in x-Richtung und
# 0 bis MAXY (jeweils einschliesslich) in y-Richtung.
# Achtung: y-Achse zeigt nach unten (wie Zeilennummern)
MAXX = 24
MAXY = 15
 
# Festlegung von Breite und Höhe einer Box in Pixel. 
# Meist sind Breite und Höhe gleich, was quadratische Boxen liefert.
SEITENLAENGE_BOX = 40
 
# Es geht auch mit Bildern (Hintergrund, Apfel, Schlangenkopf) 
# und Sound (Crash bzw. Game over).
# Suche dafür geeignete Dateien und speichere diese am besten 
# in demselben Verzeichnis wie dieses Programm. 
# In der Funktion ''lade_bilder_und_sound'' musst du 
# dann die Namen deiner Dateien (evtl. inklusive Pfad) angeben.
 
BOXEN_STATT_BILDER = True
EINFARBIGER_HINTERGRUND = True
MIT_SOUND = False
 
# Ab hier Konstanten, die von den obigen abhängen.
ANZAHL_BOXEN_X = MAXX + 1
ANZAHL_BOXEN_Y = MAXY + 1
 
FENSTER_BREITE = ANZAHL_BOXEN_X * SEITENLAENGE_BOX
FENSTER_HOEHE = ANZAHL_BOXEN_Y * SEITENLAENGE_BOX
PLATZ_FUER_TEXT = 5 * SEITENLAENGE_BOX 
 
# Farben per Rot-, Grün- und Blauwert
# (jeweils auf Skala von 0 bis 255).
# Wer will, kann hier zusätzliche eigene Farben festlegen.
#             rot  grün  blau
ROT     =    (255,    0,    0)
GRUEN   =    (  0,  255,    0)
BLAU    =    (  0,    0,  255)
GELB    =    (255,  255,    0)
MAGENTA =    (255,    0,  255)
CYAN    =    (  0,  255,  255)
WEISS   =    (255,  255,  255)
SCHWARZ =    (  0,    0,    0)
HELLGRAU =   (80,  80,  80)
DUNKELGRAU = (160,  160,  160)
HINTERGRUND_FARBE = SCHWARZ
# HINTERGRUND_FARBE = HELLGRAU
 
#
# Definition der Klasse Punkt. Bitte einfach akzeptieren.
#
class Punkt:
    def __init__(self, x, y):
        self.x = x
        self.y = y
 
    def __str__(self):
        return '(' + str(self.x) + ',' + str(self.y) + ')'
 
    def __repr__(self):
        return '(' + str(self.x) + ',' + str(self.y) + ')'
 
    def __eq__(self, other):
        return self.x == other.x and self.y == other.y
 
    def __add__(self, other):
        return Punkt(self.x + other.x, self.y + other.y)
 
    def __hash__(self):
        return hash(str(self))
# 
# Ende der Definition der Klasse Punkt.
#
 
def zeichne_box(p, farbe):
    rechteck = pygame.Rect(p.x * SEITENLAENGE_BOX + 1, p.y * SEITENLAENGE_BOX + 1, SEITENLAENGE_BOX - 1, SEITENLAENGE_BOX - 1)
    pygame.draw.rect(leinwand, farbe, rechteck)
 
def zeichne_gitter():
    for x in range(ANZAHL_BOXEN_X + 1):
        pygame.draw.line(leinwand, HELLGRAU, (x * SEITENLAENGE_BOX, 0), (x * SEITENLAENGE_BOX, FENSTER_HOEHE))
    for y in range(ANZAHL_BOXEN_Y + 1):
        pygame.draw.line(leinwand, HELLGRAU, (0, y * SEITENLAENGE_BOX), (FENSTER_BREITE, y * SEITENLAENGE_BOX))
 
def schreibe(x, y, text, groesse):
    schrift = pygame.font.SysFont('freemono', round(groesse * SEITENLAENGE_BOX))
    formatierter_text = schrift.render(text, True, WEISS, SCHWARZ)
    rechteck = formatierter_text.get_rect()
    rechteck.center = (round((x + 0.5) * SEITENLAENGE_BOX), round((y + 0.5) * SEITENLAENGE_BOX))
    leinwand.blit(formatierter_text, rechteck)
 
def schreibe_transparent(x, y, text, groesse):
    schrift = pygame.font.SysFont('freemono', round(groesse * SEITENLAENGE_BOX))
    formatierter_text = schrift.render(text, True, SCHWARZ)
    rechteck = formatierter_text.get_rect()
    rechteck.center = (round((x + 0.5) * SEITENLAENGE_BOX), round((y + 0.5) * SEITENLAENGE_BOX))
    if rechteck.x >= 0 and rechteck.y >= 0:
        text_flaeche = pygame.Surface((rechteck.x, rechteck.y))
        text_flaeche.fill(WEISS)
        text_flaeche.blit(formatierter_text, rechteck)
        text_flaeche.set_alpha(50)
        leinwand.blit(formatierter_text, rechteck)
 
def neue_apfelposition():
    a = Punkt(randrange(0, MAXX + 1), randrange(0, MAXY + 1))
    while a in schlange:
        a = Punkt(randrange(0, MAXX + 1), randrange(0, MAXY + 1))
    return a
 
def lade_bilder_und_sound():
    global hintergrundbild, bild_kopf_der_schlange, bild_apfel, apfel_ess_sound, crash_sound
 
    if not EINFARBIGER_HINTERGRUND:
        hintergrundbild = pygame.image.load('landschaft.jpg')
        hintergrundbild = pygame.transform.scale(hintergrundbild, (FENSTER_BREITE, FENSTER_HOEHE))
 
    if not BOXEN_STATT_BILDER:
        bild_apfel = pygame.image.load('apple.svg')
        bild_apfel = pygame.transform.scale(bild_apfel, (SEITENLAENGE_BOX, SEITENLAENGE_BOX))
        bild_kopf_der_schlange = pygame.image.load('Excited-Smiley-Face.svg')
        bild_kopf_der_schlange = pygame.transform.scale(bild_kopf_der_schlange, (SEITENLAENGE_BOX, SEITENLAENGE_BOX))
 
    if MIT_SOUND:
        crash_sound = pygame.mixer.Sound('mixkit-funny-game-lose-tone-2877.wav')
        apfel_ess_sound = pygame.mixer.Sound('mixkit-video-game-retro-click-237.wav')
 
def zeige_bild(bild, p):
    rechteck = pygame.Rect(p.x * SEITENLAENGE_BOX + 1, p.y * SEITENLAENGE_BOX + 1, SEITENLAENGE_BOX - 1, SEITENLAENGE_BOX - 1)
    leinwand.blit(bild, rechteck)
 
pygame.init()
uhr = pygame.time.Clock()
leinwand = pygame.display.set_mode((FENSTER_BREITE + 1, FENSTER_HOEHE + 1 + PLATZ_FUER_TEXT))
pygame.display.set_caption('Snake game')
lade_bilder_und_sound()
 
# Initialisiere die Liste, deren Einträge die Koordinaten der Quadrate der Schlange sind.
# Der 0-te Eintrag enhält die Position des Kopfes der Schlange.
laenge = 4
#I schlange = [Punkt(4, 7), Punkt(3, 7), Punkt(2, 7), Punkt(1, 7)]
# Oder besser, da abhängig von der Variablen "länge"
schlange = []
for i in range(laenge):
    schlange.insert(0, Punkt(1 + i, MAXY // 2)) 
# Und noch besser bzw. kürzer geht das so:
# schlange = [Punkt(laenge - i, MAXY // 2) for i in range(laenge)]
farbe_schlange = GRUEN
 
# Änderung der Spielerposition pro Spielzyklus:
bewegungsrichtung = Punkt(0, 0)
 
# Hilfsvariablen, anfangs am besten ignorieren.
neue_richtung = bewegungsrichtung
richtung_vor_stopp = Punkt(0, 0)
 
# Initialisiere Apfelposition (nicht auf Schlange!) und Farbe.
apfel = neue_apfelposition()
farbe_apfel = ROT
 
# Initialisierung der "Spielvariablen"
frames_per_second = FRAMES_PER_SECOND_AM_ANFANG
spiel_aktiv = True
crash = False
gefressene_aepfel = 0
 
# Hier startet die "game loop".
while spiel_aktiv:
    # Graphische Darstellung des Spielgeschehens:
 
    # Hintergrund
    if EINFARBIGER_HINTERGRUND:
        leinwand.fill(HINTERGRUND_FARBE)
    else:
        leinwand.fill(HINTERGRUND_FARBE)
        leinwand.blit(hintergrundbild, (0, 0))
 
    # Ausgabe diverser Zahlen unter dem Spielfeld
    schreibe(MAXX // 4, MAXY + 1, 'apple count: ' + str(gefressene_aepfel), 0.8)
    schreibe(3 * MAXX // 4, MAXY + 1, 'length: ' + str(laenge), 0.8)
    schreibe(MAXX // 4, MAXY + 2, 'apple: ' + str(apfel), 0.8)
    schreibe(3 * MAXX // 4, MAXY + 2, 'current length: ' + str(len(set(schlange))), 0.8)
    schreibe(MAXX // 4, MAXY + 3, 'head of snake: ' + str(schlange[0]), 0.8)
    schreibe(3 * MAXX // 4, MAXY + 3, 'frames per second: ' + str(frames_per_second), 0.8)
    text = str(schlange)
    schreibe(MAXX // 2, MAXY + 4, text, 0.6)
    schreibe(MAXX // 2, MAXY + 5, 'Space key: pause game', 0.8)
 
    # Raster zeichnen
    zeichne_gitter()
 
    # Apfel zeichnen
    if BOXEN_STATT_BILDER:
        zeichne_box(apfel, farbe_apfel)
        schreibe_transparent(apfel.x, apfel.y , str(apfel), 0.25)
    else:
        zeige_bild(bild_apfel, apfel)
        schreibe_transparent(apfel.x, apfel.y , str(apfel), 0.25)
 
    # Schlange zeichnen
    for element in schlange:
        zeichne_box(element, farbe_schlange)
        schreibe_transparent(element.x, element.y , str(element), 0.25)
    if not BOXEN_STATT_BILDER:
        zeige_bild(bild_kopf_der_schlange, schlange[0])
        schreibe_transparent(schlange[0].x, schlange[0].y , str(schlange[0]), 0.25)
 
    # Alles bis jetzt "versteckt" Gezeichnete sichtbar machen.
    pygame.display.update()
    uhr.tick(frames_per_second)
 
    # Verarbeitung von Tastatureingaben:
    for ereignis in pygame.event.get():
        if ereignis.type == QUIT:
            print("Button zum Schliessen des Pygame-Fensters angeklickt.")
            spiel_aktiv = False
        elif ereignis.type == KEYDOWN:
            if ereignis.key == K_ESCAPE:
                print("Escape-Taste gedrückt.")
                spiel_aktiv = False
            elif ereignis.key == K_q:
                print("Taste 'q' gedrückt.")
                spiel_aktiv = False
            elif ereignis.key == K_SPACE:
                print("Leer-Taste gedrückt.")
                if bewegungsrichtung != Punkt(0, 0):
                    richtung_vor_stopp = bewegungsrichtung
                    bewegungsrichtung = Punkt(0, 0)
                else:
                    bewegungsrichtung =richtung_vor_stopp
            else:            
                if ereignis.key == K_r:
                    print("Pfeiltaste links gedrückt.")
                    neue_richtung = Punkt(-1, -1)
                elif ereignis.key == K_f:
                    print("Pfeiltaste rechts gedrückt.")
                    neue_richtung = Punkt(-1, 1)
                elif ereignis.key == K_t:
                    print("Pfeiltaste hoch gedrückt.")
                    neue_richtung = Punkt(1, -1)
                elif ereignis.key == K_g:
                    print("Pfeiltaste runter gedrückt.")
                    neue_richtung = Punkt(1, 1)
                # Die folgende if-Bedingung verhindert, dass die
                # Snake die Richtung umkehren kann (und mit sich selbst kollidiert).
                if schlange[1] != schlange[0] + neue_richtung:
                    bewegungsrichtung = neue_richtung
 
    # Bewegen der Schlange:
    if bewegungsrichtung != Punkt(0, 0):
        # Falls die Schlange die gewünschte Länge hat:
        # Beseitige das letzte Element aus der Liste "schlange".
        if len(schlange) == laenge:
            schlange.pop()
 
        # Neues Feld, auf das sich die Schlange bewegt:
        neue_position = schlange[0] + bewegungsrichtung
 
        # Verhalten am Spielfeldrand:
        if neue_position.x < 0:
            neue_position.x = MAXX
        if neue_position.x > MAXX:
            neue_position.x = 0
        if neue_position.y < 0:
            neue_position.y = MAXY
        if neue_position.y > MAXY:
            neue_position.y = 0
 
        # Selbstkollision:
        if neue_position in schlange:
            crash = True
            spiel_aktiv = False
            if MIT_SOUND:
                pygame.mixer.Sound.play(crash_sound)
        else:
            # Hänge die neue Position vorne an die Liste "schlange".
            schlange.insert(0, neue_position)
            # Apfel erreicht?
            if neue_position == apfel:
                gefressene_aepfel = 1
                if MIT_SOUND:
                    pygame.mixer.Sound.play(apfel_ess_sound)
                laenge = laenge * 2
                frames_per_second = frames_per_second + VERGROESSERUNG_PRO_APFEL 
                apfel = neue_apfelposition()
# Ende der game loop.
 
# Nach Abbruch oder Crash:
 
if crash:
    schreibe(MAXX // 2, MAXY // 2, 'GAME OVER', 2)
    schreibe(MAXX // 2, MAXY // 2 + 3, 'press any key', 1)
    pygame.display.update()
    pygame.time.delay(500)
    for ereignis in pygame.event.get():
        pygame.time.delay(100)
    while pygame.event.get() == []:
        pygame.time.delay(100)
 
pygame.quit()
exit()

Überlege dir, wie man das Spiel weiterentwickeln könnte. Verstehe das Programm dazu möglichst gut bzw. wenigstens so weit wie nötig.

einige Ideen

einige Ideen

  • Füge ein Hindernis ein: Die Schlange stirbt, wenn sie dagegen fährt. Das Hindernis könnte sich auch bewegen (hin und her oder gar Richtung Schlange).
  • Programmiere eine zweite Schlange, die sich etwa mit den Tasten a, s, d, w steuern lässt, so dass ihr gegeneinander spielen könnt (Achtung, das q für den Abbruch ist gefährlich nah an diesen Tasten.) Wer verschlingt mehr Äpfel? Zeige den jeweiligen Punktestand an. Was passiert und wer ist schuld, wenn es eine Kollision gibt? Endet das Spiel oder muss man einen Apfel abgeben oder wird man länger/kürzer? Vielleicht gibt es auch gar keine Äpfel mehr und es geht nur darum, den Gegner zu einer Kollision zu zwingen. Eventuell mehrere Runden hintereinander spielen.
  • Die Schlange benötigt Energie für's Herumschleichen; zum Beispiel könnte sie alle 100 Schritte einen Apfel verlieren.
  • Statt einem Apfel könnte es mehrere Äpfel geben (die nur eine begrenzte Zeit lang existieren). Hier wäre es vermutlich sinnvoll, eine Liste mit den aktuellen Apfelpositionen zu verwenden.
  • Es könnte auch mehrere Hindernisse geben oder mehrere Schlangen.
  • Verschiedene Level einführen.

Schwieriger:

  • Sprites
  • gleichmässige Bewegung
  • Kopf der Schlange (also geeignetes Bild) zeigt in Laufrichtung
  • Schlange schlanker (also Rechtecke statt Quadrate mit richtig gekrümmten Abbiegefeldern)
  • Spielen übers Netzwerk?

... wenn du eigene Bilder oder Sounds integrieren willst

Vorbereitet ist das Programm so, dass du

  • Bilder für den Hintergrund oder
  • Bilder für den Apfel und den Schlangenkopf oder
  • Sounds für Spielende und Apfelfressen

leicht einbinden kannst (du kannst beispielsweise nur ein Hintergrundbild einbinden).

Dazu musst du geeignete Dateien bereitstellen (am besten in demselben Verzeichnis wie das Programm) und

  • in der Funktion lade_bilder_und_sound die entsprechenden Dateinamen (eventuell inklusive Pfad) angeben und
  • die booleschen Konstanten EINFARBIGER_HINTERGRUND (Hintergrund), BOXEN_STATT_BILDER (Apfel und Schlangenkopf) und MIT_SOUND (Spielende und Apfelfressen) entsprechend anpassen, d.h. auf False bzw. False bzw.True setzen.
  • lehrkraefte/snr/informatik/glf22/python/snake.txt
  • Last modified: 2023/02/14 20:01
  • by Olaf Schnürer