~~NOTOC~~ 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. ==== Eventuelle Nachträge ==== * (2aLIM): [[lehrkraefte:snr:informatik:glf22:python:simulationen:ziegenproblem|Simulation des Ziegenproblems]] * [[lehrkraefte:snr:informatik:glf22:python:simulationen:erwartungswerte-mathematisch|Mathematische Begrüdung für die durchschnittliche Wurfanzahl, bis zwei Sechser direkt hintereinander kommen]] ====== 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. ===== Aufgabe: A ball game - grobes Verstehen (und Korrigieren) eines Python-Programms ===== Hist ist ein Link zu einem in ''pygame'' programmierten Spiel (bitte nur kurz ausprobieren). * [[lehrkraefte:snr:informatik:glf22:python:snake:ballgame-fehlerhaftes-programm|Link zum Programm ''ball-game-zu-verbessern.py'']] 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: * Programmiere online: https://trinket.io/features/pygame 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). 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"). 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.) ===== Richtung Snake: Listen in Python ===== 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 [[lehrkraefte:snr:informatik:glf22:python:listen|Listen]] des Programmierkurses über Listen zu verweisen, erkläre ich hier direkt, was für Snake nötig ist. Per Python-Shell erklären oder direkt das Programm laufen lassen, am besten mit Breakpoint ganz am Anfang. # 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). {{lehrkraefte:snr:informatik:glf22:python:snake-mit-listen.jpg}} ===== Aufgabe: Ein Snake-Programm in Grundzügen verstehen ===== 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.) * [[lehrkraefte:snr:informatik:glf22:python:snake:snake-zu-verbessern|Link zum Programm ''snake-zu-verbessern.py'']] 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. 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. * 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. ===== Link zur Kursseite ===== [[lehrkraefte:snr:informatik:glf22|Zur Kursseite]]