Differences
This shows you the differences between two versions of the page.
| Both sides previous revision Previous revision Next revision | Previous revision | ||
| lehrkraefte:snr:informatik:glf22:python:snake [2023/01/27 06:04] – [Aufgabe: Ein Snake-Programm in Grundzügen verstehen] Olaf Schnürer | lehrkraefte:snr:informatik:glf22:python:snake [2023/02/14 19:01] (current) – [Richtung Snake: Listen in Python] Olaf Schnürer | ||
|---|---|---|---|
| Line 1: | Line 1: | ||
| + | ~~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: | ||
| + | * [[lehrkraefte: | ||
| + | |||
| + | ====== 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 ===== | ||
| + | |||
| + | <WRAP center round todo> | ||
| + | Hist ist ein Link zu einem in '' | ||
| + | |||
| + | * [[lehrkraefte: | ||
| + | |||
| + | <hidden Falls das Programm bei dir nicht läuft:> | ||
| + | |||
| + | <WRAP center round info box> | ||
| + | Es könnte sein, dass pygame nicht installiert ist: Installation mit '' | ||
| + | |||
| + | Alternativ kannst du online programmieren: | ||
| + | |||
| + | * Programmiere online: https:// | ||
| + | |||
| + | Lösche das Programm dort und ersetze es durch das Programm " | ||
| + | |||
| + | Die Tastatursteuerung ist online wohl etwas langsam. | ||
| + | </ | ||
| + | </ | ||
| + | |||
| + | ---- | ||
| + | |||
| + | <WRAP center round box> | ||
| + | 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. | ||
| + | |||
| + | <WRAP center round box> | ||
| + | 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. | ||
| + | </ | ||
| + | |||
| + | <WRAP center round box> | ||
| + | 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. | ||
| + | |||
| + | <WRAP center round box> | ||
| + | === Teilaufgabe 1 === | ||
| + | |||
| + | Hilf dem Programmierer, | ||
| + | * (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, | ||
| + | |||
| + | Dafür musst du nur etwa 20 Zeilen ab Zeile 176 ändern, das gesamte restliche Programm bleibt unverändert (vgl. Kommentar in Zeile 173). | ||
| + | |||
| + | <hidden Hinweise> | ||
| + | <WRAP center round box> | ||
| + | Die gesamte '' | ||
| + | |||
| + | Die y-Achse des " | ||
| + | |||
| + | Die aktuelle Position des grünen Quadrats ist in der Variablen '' | ||
| + | * '' | ||
| + | * '' | ||
| + | Ü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 '' | ||
| + | * $y$-Richtung von '' | ||
| + | </ | ||
| + | |||
| + | </ | ||
| + | |||
| + | </ | ||
| + | |||
| + | <WRAP center round box> | ||
| + | === Teilaufgabe 2 === | ||
| + | |||
| + | Hilf dem Programmierer, | ||
| + | |||
| + | 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 " | ||
| + | |||
| + | <hidden Hinweis> | ||
| + | <WRAP center round box> | ||
| + | Beobachte zuerst genau, an welchen der drei Spielfeldränder (oben, rechts, unten) das Reflexionsverhalten falsch ist. | ||
| + | |||
| + | Die '' | ||
| + | |||
| + | Die aktuelle Position des Balls ist in der Variablen '' | ||
| + | * '' | ||
| + | * '' | ||
| + | |||
| + | 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 '' | ||
| + | * '' | ||
| + | * '' | ||
| + | In jedem Durchlauf der "game loop" wird (in Zeile 215) dieser Vektor zur Position '' | ||
| + | |||
| + | Passe nun jeweils die Zeilen nach den drei '' | ||
| + | </ | ||
| + | |||
| + | </ | ||
| + | </ | ||
| + | |||
| + | <WRAP center round box> | ||
| + | === 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. | ||
| + | </ | ||
| + | |||
| + | <WRAP center round box> | ||
| + | === 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 '' | ||
| + | * Ändere die Steuerung (vermutlich nicht so leicht; braucht u.a. '' | ||
| + | * 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 ===== | ||
| + | |||
| + | <WRAP center round info box> | ||
| + | Um Snake zu programmieren, | ||
| + | |||
| + | In gewisser Weise kommen wir hier an's Ende des Programmierkurses: | ||
| + | </ | ||
| + | |||
| + | Statt auf den Abschnitt [[lehrkraefte: | ||
| + | |||
| + | <hidden 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. | ||
| + | <code python listen-demo.py> | ||
| + | # Beispiel 1: | ||
| + | # Top 5 der Vornamen in der italienischen Schweiz 2021 laut BFS, https:// | ||
| + | namensliste = [' | ||
| + | print(namensliste) | ||
| + | print(namensliste[3]) | ||
| + | print(namensliste[0]) | ||
| + | namensliste[3] = ' | ||
| + | print(namensliste) | ||
| + | print(" | ||
| + | print(" | ||
| + | print(len(namensliste)) | ||
| + | for name in namensliste: | ||
| + | print(' | ||
| + | namensliste.insert(0, | ||
| + | print(namensliste) | ||
| + | namensliste.insert(3, | ||
| + | print(namensliste) | ||
| + | namensliste.pop() | ||
| + | print(namensliste) | ||
| + | namensliste.pop(2) | ||
| + | print(namensliste) | ||
| + | print(namensliste[1: | ||
| + | |||
| + | # Beispiel 2: | ||
| + | notenliste=[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: | ||
| + | liste_der_wuerfe.insert(0, | ||
| + | print(liste_der_wuerfe) | ||
| + | </ | ||
| + | </ | ||
| + | |||
| + | ---- | ||
| + | |||
| + | Ausserdem sollte man verstehen, warum eine Liste die naheliegende Datenstruktur für Snake ist (verbale Erklärung mit Snake-Beispielprogramm, | ||
| + | |||
| + | <hidden Tafelfoto dazu> | ||
| + | {{lehrkraefte: | ||
| + | </ | ||
| + | ===== Aufgabe: Ein Snake-Programm in Grundzügen verstehen ===== | ||
| + | |||
| + | <WRAP center round todo> | ||
| + | Hist ist ein Link zu einem in '' | ||
| + | |||
| + | (Zusammen die per ''## | ||
| + | |||
| + | * [[lehrkraefte: | ||
| + | |||
| + | Korrigiere dieses Programm, so dass es dem üblichen Snake ähnelt: | ||
| + | * Statt mit den Tasten '' | ||
| + | * Wenn die Schlange einen Apfel frisst, soll die unter dem Spielfeld angezeigte Variable '' | ||
| + | * 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. | ||
| + | |||
| + | <hidden Für diejenigen, die Online programmieren (da dort f-strings wohl nicht funktionieren; | ||
| + | <code python 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, | ||
| + | # 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 '' | ||
| + | # 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 | ||
| + | GRUEN | ||
| + | BLAU = ( 0, 0, 255) | ||
| + | GELB = (255, 255, 0) | ||
| + | MAGENTA = (255, 0, 255) | ||
| + | CYAN = ( 0, 255, 255) | ||
| + | WEISS | ||
| + | SCHWARZ = ( 0, 0, 0) | ||
| + | HELLGRAU = | ||
| + | DUNKELGRAU = (160, 160, 160) | ||
| + | HINTERGRUND_FARBE = SCHWARZ | ||
| + | # HINTERGRUND_FARBE = HELLGRAU | ||
| + | |||
| + | # | ||
| + | # Definition der Klasse Punkt. Bitte einfach akzeptieren. | ||
| + | # | ||
| + | class Punkt: | ||
| + | def __init__(self, | ||
| + | self.x = x | ||
| + | self.y = y | ||
| + | |||
| + | def __str__(self): | ||
| + | return ' | ||
| + | |||
| + | def __repr__(self): | ||
| + | return ' | ||
| + | |||
| + | def __eq__(self, | ||
| + | return self.x == other.x and self.y == other.y | ||
| + | |||
| + | def __add__(self, | ||
| + | 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, | ||
| + | rechteck = pygame.Rect(p.x * SEITENLAENGE_BOX + 1, p.y * SEITENLAENGE_BOX + 1, SEITENLAENGE_BOX - 1, SEITENLAENGE_BOX - 1) | ||
| + | pygame.draw.rect(leinwand, | ||
| + | |||
| + | def zeichne_gitter(): | ||
| + | for x in range(ANZAHL_BOXEN_X + 1): | ||
| + | pygame.draw.line(leinwand, | ||
| + | for y in range(ANZAHL_BOXEN_Y + 1): | ||
| + | pygame.draw.line(leinwand, | ||
| + | |||
| + | def schreibe(x, y, text, groesse): | ||
| + | schrift = pygame.font.SysFont(' | ||
| + | formatierter_text = schrift.render(text, | ||
| + | rechteck = formatierter_text.get_rect() | ||
| + | rechteck.center = (round((x + 0.5) * SEITENLAENGE_BOX), | ||
| + | leinwand.blit(formatierter_text, | ||
| + | |||
| + | def schreibe_transparent(x, | ||
| + | schrift = pygame.font.SysFont(' | ||
| + | formatierter_text = schrift.render(text, | ||
| + | rechteck = formatierter_text.get_rect() | ||
| + | rechteck.center = (round((x + 0.5) * SEITENLAENGE_BOX), | ||
| + | if rechteck.x >= 0 and rechteck.y >= 0: | ||
| + | text_flaeche = pygame.Surface((rechteck.x, | ||
| + | text_flaeche.fill(WEISS) | ||
| + | text_flaeche.blit(formatierter_text, | ||
| + | text_flaeche.set_alpha(50) | ||
| + | leinwand.blit(formatierter_text, | ||
| + | |||
| + | def neue_apfelposition(): | ||
| + | a = Punkt(randrange(0, | ||
| + | while a in schlange: | ||
| + | a = Punkt(randrange(0, | ||
| + | return a | ||
| + | |||
| + | def lade_bilder_und_sound(): | ||
| + | global hintergrundbild, | ||
| + | |||
| + | if not EINFARBIGER_HINTERGRUND: | ||
| + | hintergrundbild = pygame.image.load(' | ||
| + | hintergrundbild = pygame.transform.scale(hintergrundbild, | ||
| + | |||
| + | if not BOXEN_STATT_BILDER: | ||
| + | bild_apfel = pygame.image.load(' | ||
| + | bild_apfel = pygame.transform.scale(bild_apfel, | ||
| + | bild_kopf_der_schlange = pygame.image.load(' | ||
| + | bild_kopf_der_schlange = pygame.transform.scale(bild_kopf_der_schlange, | ||
| + | |||
| + | if MIT_SOUND: | ||
| + | crash_sound = pygame.mixer.Sound(' | ||
| + | apfel_ess_sound = pygame.mixer.Sound(' | ||
| + | |||
| + | def zeige_bild(bild, | ||
| + | rechteck = pygame.Rect(p.x * SEITENLAENGE_BOX + 1, p.y * SEITENLAENGE_BOX + 1, SEITENLAENGE_BOX - 1, SEITENLAENGE_BOX - 1) | ||
| + | leinwand.blit(bild, | ||
| + | |||
| + | pygame.init() | ||
| + | uhr = pygame.time.Clock() | ||
| + | leinwand = pygame.display.set_mode((FENSTER_BREITE + 1, FENSTER_HOEHE + 1 + PLATZ_FUER_TEXT)) | ||
| + | pygame.display.set_caption(' | ||
| + | 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 " | ||
| + | schlange = [] | ||
| + | for i in range(laenge): | ||
| + | schlange.insert(0, | ||
| + | # 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, | ||
| + | neue_richtung = bewegungsrichtung | ||
| + | richtung_vor_stopp = Punkt(0, 0) | ||
| + | |||
| + | # Initialisiere Apfelposition (nicht auf Schlange!) und Farbe. | ||
| + | apfel = neue_apfelposition() | ||
| + | farbe_apfel = ROT | ||
| + | |||
| + | # Initialisierung der " | ||
| + | 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, | ||
| + | |||
| + | # Ausgabe diverser Zahlen unter dem Spielfeld | ||
| + | schreibe(MAXX // 4, MAXY + 1, 'apple count: ' + str(gefressene_aepfel), | ||
| + | schreibe(3 * MAXX // 4, MAXY + 1, ' | ||
| + | schreibe(MAXX // 4, MAXY + 2, ' | ||
| + | schreibe(3 * MAXX // 4, MAXY + 2, ' | ||
| + | schreibe(MAXX // 4, MAXY + 3, 'head of snake: ' + str(schlange[0]), | ||
| + | schreibe(3 * MAXX // 4, MAXY + 3, ' | ||
| + | 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, | ||
| + | schreibe_transparent(apfel.x, | ||
| + | else: | ||
| + | zeige_bild(bild_apfel, | ||
| + | schreibe_transparent(apfel.x, | ||
| + | |||
| + | # Schlange zeichnen | ||
| + | for element in schlange: | ||
| + | zeichne_box(element, | ||
| + | schreibe_transparent(element.x, | ||
| + | if not BOXEN_STATT_BILDER: | ||
| + | zeige_bild(bild_kopf_der_schlange, | ||
| + | schreibe_transparent(schlange[0].x, | ||
| + | |||
| + | # Alles bis jetzt " | ||
| + | pygame.display.update() | ||
| + | uhr.tick(frames_per_second) | ||
| + | |||
| + | # Verarbeitung von Tastatureingaben: | ||
| + | for ereignis in pygame.event.get(): | ||
| + | if ereignis.type == QUIT: | ||
| + | print(" | ||
| + | spiel_aktiv = False | ||
| + | elif ereignis.type == KEYDOWN: | ||
| + | if ereignis.key == K_ESCAPE: | ||
| + | print(" | ||
| + | spiel_aktiv = False | ||
| + | elif ereignis.key == K_q: | ||
| + | print(" | ||
| + | spiel_aktiv = False | ||
| + | elif ereignis.key == K_SPACE: | ||
| + | print(" | ||
| + | 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(" | ||
| + | neue_richtung = Punkt(-1, -1) | ||
| + | elif ereignis.key == K_f: | ||
| + | print(" | ||
| + | neue_richtung = Punkt(-1, 1) | ||
| + | elif ereignis.key == K_t: | ||
| + | print(" | ||
| + | neue_richtung = Punkt(1, -1) | ||
| + | elif ereignis.key == K_g: | ||
| + | print(" | ||
| + | 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 " | ||
| + | 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.insert(0, | ||
| + | # 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() | ||
| + | </ | ||
| + | </ | ||
| + | </ | ||
| + | |||
| + | <WRAP center round todo> | ||
| + | Überlege dir, wie man das Spiel weiterentwickeln könnte. Verstehe das Programm dazu möglichst gut bzw. wenigstens so weit wie nötig. | ||
| + | |||
| + | <hidden 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 '' | ||
| + | * Die Schlange benötigt Energie für's Herumschleichen; | ||
| + | * 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 === | ||
| + | |||
| + | <WRAP center round todo> | ||
| + | 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 '' | ||
| + | * die booleschen Konstanten '' | ||
| + | </ | ||
| + | |||
| + | |||
| + | |||
| + | |||
| + | |||
| + | ===== Link zur Kursseite ===== | ||
| + | |||
| + | [[lehrkraefte: | ||
| + | |||