snake mit pygame

Stellt hier eure Projekte vor.
Internetseiten, Skripte, und alles andere bzgl. Python.
Xynon1
User
Beiträge: 1267
Registriert: Mittwoch 15. September 2010, 14:22

Habe mal ein Snake-Spiel mit pygame angefangen. http://www.python-forum.de/pastebin.php?mode=view&s=175

Ist noch nicht viel, nur das Grundlegende: Bewegen, Fressen und Sterben. :D
Die Grafik habe ich selbst noch nicht, zum einfachen Testen hatte ich nur schnell 3 unterschiedliche Farbkreise genutzt, wer es also testen möchte sollte dies auch tun. Man sollte ein "img"-Verzeichnis im selben Verzeichnis wie das Script haben und in diesem sollten sich dann "head.png", "part.png" und "feed.png" befinden. Ich hatte 32x32 Bilder, muss nicht sein, aber die Proportion sollte gleich bleiben.

Wenn sich jemand mal die Zeit nimmt und das Script durchsieht wo man was verbessern könnte oder gänzlich was rausschmeißt, dann immer her mit der Kritik. :mrgreen:
Achso, im übrigen mein erstes pygame-Programm, also bitte mein Konzept mal überprüfn ob das so in Ordnung ist.

Edit: Frei Probleme die ich im Moment habe:
- zum einen, das manchmal einige Objekte bei der Initialisierung nicht da sind - was ich mir bisher noch nicht erklären kann
- zum anderen das wenn sich die zwei Köpfe treffen nur einer drauf geht, ist aber klar, weil das Kollisionsevent ja nur von einem Ausgewertet wird und der andere dann nicht mehr existiert.
- zum letzten, ich habe die Regeln für die Kollision so gebaut, das der Schlangenkopf immer mit seinem ersten Körperteil kollidieren darf, nicht aber mit dem zweiten, manchmal killt er sich dadurch beim aufsammeln des zweiten Bausteines, wenn man zu scharf in die Kurve geht. Mögliche Lösung die mir dazu einfallen sind nur SPEED(das Schritttempo) rauf und Feld etwas Größer machen.

Edit:
Source Code findet man unter http://github.com/xynon/snake
Weiteres Thread zu dem Thema:
http://www.python-forum.de/viewtopic.php?f=1&t=25949
http://www.python-forum.de/viewtopic.php?f=4&t=26037
Zuletzt geändert von Xynon1 am Donnerstag 14. April 2011, 15:11, insgesamt 2-mal geändert.
Traue keinem Computer, den du nicht aus dem Fenster werfen kannst.
Xynon auf GitHub
Benutzeravatar
kaytec
User
Beiträge: 608
Registriert: Dienstag 13. Februar 2007, 21:57

Hallo Xynon1,

Die Kollisionsabfrage über pygame ist für meine Begriffe übertrieben, denn eigentlich ist das gesamte Spielfeld ein Raster mit einzelnen Quadraten von der Größe 32 x 32. Genau auf diesem Raster läuft die Schlange und liegt auch das Fressen. Nur bei einer einzigen Position besteht der Treffer und so muß auch nur auf diese geprüft werden. So ensteht auch nicht bei "Kurvenfahrt" eine weitere Kollision.

Gruß Frank
Xynon1
User
Beiträge: 1267
Registriert: Mittwoch 15. September 2010, 14:22

Ich weiß, sowas hatte ich schon mal mit Tkinter und einmal als Terminal-Programm gemacht. Aber genau dieses "Retro-Snake" wollte ich diesmal nicht bauen, denn pygame ist für ein feineres Raster schnell genug. Die Kurvenfahrt habe ich schon unterbunden in dem ich die Positionen speichere. Dazu speichert jedes Segment der Schlange die Position auf die es sich bewegt und gibt diese dann nach unten weiter, so tritt immer ein Segement in die "Fußstapfen" des vorherigen.
Traue keinem Computer, den du nicht aus dem Fenster werfen kannst.
Xynon auf GitHub
deets

Das Kollisionsproblem kannst du zB durch die Verwendung von sowas wie Box2D loesen. Das ist eine Physik-Engine, die fuer deinen Fall ausreichen sollte. Das besondere ist, dass sie "sweeping" beherrscht - d.h. sie interpoliert zwischenschritte in der Physiksimulation, wenn du schnell bewegende Objekte hast, die sonst durch zB waende durchfliegen wuerden.
Xynon1
User
Beiträge: 1267
Registriert: Mittwoch 15. September 2010, 14:22

Ist das nicht eine reine C++ Lib? - gibt es dafür schon einen Python Wrapper?
Aber bisher hatte die Kollisionserkennung gut funktioniert, einzig und allein ein paar kleinere Logikprobleme. <-- und ich denke ich sollte erstmal mit dem Standard pygame arbeiten bevor ich mir irgendwelche Zusatztpakete hole.
Traue keinem Computer, den du nicht aus dem Fenster werfen kannst.
Xynon auf GitHub
deets

Ja, es gibt einen Wrapper.

Natuerlich musst du nicht Box2D verwenden. Aber es hat halt Probleme geloest, die du selbst versuchst anzugehen. Und darueber hinaus ist eine Physik-Engine ein interessantes + hilfreiches Ding.
Xynon1
User
Beiträge: 1267
Registriert: Mittwoch 15. September 2010, 14:22

Box2D sieht auf den ersten Eindruck schon mal sehr gut aus, nur welche Problemlösungen wären das im Detail für mein Script - oder war das jetzt ein Pauschalausage? Denn bisher sehe ich (noch) keinen direkten Nutzen für ein Snake-Programm.
Ansonsten, klar ist eine Physik-Engine sehr hilfreich, aber meist machen sie viele Probleme auch etwas komplexer. Wenn damit einiges an Arbeit wegfällt, sehe ich natürlich keinen Grund diese nicht zu nutzen.
Traue keinem Computer, den du nicht aus dem Fenster werfen kannst.
Xynon auf GitHub
Benutzeravatar
snafu
User
Beiträge: 6862
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

@Xynon1:

Sehe ich das richtig, dass du in der `__init__()`-Methode von `SnakeGroup()` (Zeile 25) einfach nur die von der Basisklasse wrappst, ohne dass du Änderungen vorgenommen hast? In diesem Fall kannst du die `__init__()`-Methode auch einfach weglassen. Beispiel:

Code: Alles auswählen

>>> class MyString(str):
...     @property
...     def length(self):
...         return len(self)
...     
...     
>>> s = MyString('foo')
>>> s.length
3
Das von dir verwendete Konstrukt nutzt man ja nur, weil die eigene `__init__()`-Methode die andere überschrieben hat und nicht etwa, weil man das grundsätzlich nach dem Erben tun müsste. Es geht halt darum, das "Original" in dem Fall explizit aufzurufen, da dies nach dem Überschreiben nicht von selbst geschieht. Ein ganz gutes Beispiel für diese Technik sieht man ja auch beim Vererben von Qt-Klassen, wo es ja sogar ganz andere Methoden als `__init__()` sind, welche aus diversen Gründen direkt über die Basisklasse aufgerufen werden, nachdem man irgendwelche Vorbehandlungen gemacht hat.
Xynon1
User
Beiträge: 1267
Registriert: Mittwoch 15. September 2010, 14:22

Danke, das wusste ich nicht, bzw. ist mir das nie so bewusst gewesen. Ist aber wenn man darüber nachdenkt völlig logisch.

Edit: Das dritte Problem ist gelöst, zu scharf in die Kurve ist zwar immer noch Selbstmord(hier werde ich wohl doch ein etwas größeres Raster einbauen müssen), aber das eigentliche Problem lag woanders. Bei den Aktualisierungen der Schlangenteile wurde nicht auf die Reihenfolge geachtet und so kam es beim hinzufügen eines Segmentes dazu, das die Schlange nicht in der Reihenfolge einzelnen Teile aktualisiert wurde. Diese sind in der "pygame.sprite.Group" gewesen, welche aber nur in einem Wörterbuch verwaltet werden. Lösung war ein "pygame.sprite.OrderedUpdates" Objekt zunutzen, welches ein entfernter Verwanter von der "Group" ist. Konnte also einfach ersetzt werden.
Und erstens hat sich scheinbar von selbst erledigt, wenn man das Spielfeld größer macht. Obwohl ich eigendlich die "random.place"-Methode(an der das Warscheinlich liegt bzw. an der zugehörigen "is_free"-Methode) so gestaltet habe das die Segmente immer gesetzt werden. Vieleicht könnte jemand von euch noch mal gezielt drauf schauen ob ich da etwas übersehe.

Wenn es Fragen zum Script gibt oder irgendetwas unverständlich ist, bitte Nachfragen. Um eine Dokumentation werde ich mit der nächsten "Version" mit rausgeben.

Noch eine Frage, hat sich jemand schonmal damit auseinander gesetzt wie man Ressourcen wie Bilder am besten verwaltet? Das was ich Momentan mache gefällt mir nicht wirklich. Denn jedes mal eine Modulvariable als Konstante für jede Bilddatei, geht hier zwar noch, doch in einem größeren Projekt ist das sicher nicht sehr Praktisch. Was gibt es in der Richtung für Ansätze?
Traue keinem Computer, den du nicht aus dem Fenster werfen kannst.
Xynon auf GitHub
Xynon1
User
Beiträge: 1267
Registriert: Mittwoch 15. September 2010, 14:22

So das ist erstmal den nächsten Stand http://www.python-forum.de/pastebin.php?mode=view&s=176

Das was im obrigen Post steht hat sich geändert. Dazu habe ich die Images nun skalierbar gemacht, so das man nicht das Image ändern muss nur um es auf einer anderen Skalierung spielen zu können. Zu dem fressen die Schlangen sich jetzt auch gegenseitig.

Aber ihr solltet es unbedingt testen :mrgreen:, wie die Schlangen sich jetzt schlängeln, sieht einfach zu herrlich aus.
Wer zu Faul ist sich schnell selbst drei Images zubasteln, hier sind die mit den ich es getestet habe:
http://image-upload.de/image/q47UmU/a80ab7b964.png feed.png
http://image-upload.de/image/KoKGf9/b604b8c850.png head.png
http://image-upload.de/image/XFYfG4/56a8b1b4a8.png body.png
Traue keinem Computer, den du nicht aus dem Fenster werfen kannst.
Xynon auf GitHub
Lasse
User
Beiträge: 112
Registriert: Donnerstag 3. Februar 2011, 18:25

Hallo,
Schönes Spiel!
Ich habe mal ein paar Fragen:
1. Wenn ich auf das X zum Spielbeenden gehe wird das Programm nicht sauber beendet, sondern es gibt einen Fehler in Linie 380:
pygame.error: display Surface quit
2. Das Programm müsste sich doch eigendlich automatisch beenden, oder den Spieler fragen, ob er eine neue Runde spielen möchte.
3. Ist es gewollt, dass die zweite Schlange sich nicht bewegt?
4. Wenn der Kopf zufällig beim Spielstart auf einem Fressen steht hat man schon eine Schwanzsegment.

PS: Ich habe das Programm unter Version 3 getestet. Mit den nötigen Veränderungen.
Xynon1
User
Beiträge: 1267
Registriert: Mittwoch 15. September 2010, 14:22

1. ist mir auch schon aufgefallen, warscheinlich weil ich mitten in der Laufzeit mit "pygame.quit()" abbreche. Was mir sauberer erscheint als das in den Tutorials genutztem "sys.exit()", wo dieser Fehler nicht kommen würde, da einfach der Prozess beendet wird.
Ich habe aber bisher noch keine Idee :K, wie man das bei "pygame.quit()" anstellt, das nicht der Fehler kommt, außer ich fange einfach die Ausnahme ab. Was aber auch nicht Sinn der Sache ist. Also im Moment fande ich es nicht so schlimm, da das Programm zu dem Zeitpunkt schon beendet ist.
Edit: Habe mal kurz nachgelesen und man sollte "sys.exit()" nutzen bzw. das Programm auf normalem Weg beenden.
Edit2: Ich habe mich für den normalen Weg entschieden, indem ich die enlos Schleife einer Variable übergeben habe und diese dort wo "pygame.quit()" aufgerufen habe, auf False gesetzt. Damit wird das Programm sauber beendet.

2. :D - sicher nur soweit war ich noch gar nicht.

3. Man muss auch die zweite Steuerung nutzen :wink:, die zweite Schlange liegt auf "list('WASD')".
Edit: bzw. die erste, welches die Pfeiltasten sind. Kann man einfach bei der Snake-Instanz festlegen mit "snake.keys = K_, K_, K_, K_" welche den pygame-Keys für die Tasten entsprechen.

4. Bin schon dran das zu unterbinden.
Traue keinem Computer, den du nicht aus dem Fenster werfen kannst.
Xynon auf GitHub
Xynon1
User
Beiträge: 1267
Registriert: Mittwoch 15. September 2010, 14:22

4. ist erledigt

und es gibt jetzt Wälle, welche man anhand eines Rechteckes angibt. Diese können dann mit einem Template Objekt gefüllt werden.
http://www.python-forum.de/pastebin.php?mode=view&s=177
Traue keinem Computer, den du nicht aus dem Fenster werfen kannst.
Xynon auf GitHub
Lasse
User
Beiträge: 112
Registriert: Donnerstag 3. Februar 2011, 18:25

Hallo Xynon1,
Snake zu spielen macht richtig Spaß aber,
ich habe gerade noch einen Fehler in der neuen Version entdeckt:
beim Zusammmenstoß von zwei Schlangen:
Traceback (most recent call last):
File "C:\XXX\snake.py", line 438, in <module>
collide_snake(snake, snakes.sprites()):
File "C:\XXX\snake.py", line 376, in collide_snake
if type(sprite) is Snake:
NameError: global name 'sprite' is not defined
EDIT: Fehler tritt beim Zusammenstoß nicht immer auf.
Xynon1
User
Beiträge: 1267
Registriert: Mittwoch 15. September 2010, 14:22

Danke, aber ist schon behoben. Lag daran das ich den Namen "sprite" in der Funktion umbenannt hatte.
Genau genommen habe ich schon einen neuen Stand der schon ein ganzes Stück weiter ist. Ich überlege nnur gerade wie(bzw. wo) ich den am besten online stelle, da das programm etwas größer geworden ist und jetzt mehrere Dateien enthält.
Traue keinem Computer, den du nicht aus dem Fenster werfen kannst.
Xynon auf GitHub
Xynon1
User
Beiträge: 1267
Registriert: Mittwoch 15. September 2010, 14:22

So ist jetzt auf GitHub. https://github.com/xynon/snake
Momentan muss man zum starten ins Verzeichnis "source" und die "main.py" ausführen.
Traue keinem Computer, den du nicht aus dem Fenster werfen kannst.
Xynon auf GitHub
Xynon1
User
Beiträge: 1267
Registriert: Mittwoch 15. September 2010, 14:22

Ein paar Änderungen gab es jetzt, es gibt ein paar neue Spielmodifikationen, welche man in der config.py einstellen kann. z.B. den GLOBE-Modus, welches der Schlange erlaubt am Rand raus zu fahren und auf der anderen Seite rein.
Ebenso kann jetzt das erreichen des Zieles des Spieles geändert werden, es gibt also nicht nur mehrere Leben, sondern auch die Möglichkeit die ganze/halbe/stück Schlange zu verlieren. Seht es euch einfach mal an.

Die verschiedenen Schlangen haben jetzt auch verschiedene Farben, um sie endlich unterscheiden zu können.
Traue keinem Computer, den du nicht aus dem Fenster werfen kannst.
Xynon auf GitHub
Xynon1
User
Beiträge: 1267
Registriert: Mittwoch 15. September 2010, 14:22

Ich schreib hier mit mir selbst 8).
Jetzt sind noch etwas Ton hinzugekommen.

Wenn jemand Verbesserungsvorschläge hat, sei es im Quellcode oder im Spiel selbst, immer her damit. Grafiken, vorallem das Level-(ähm nennen wir es mal) "Design" muss ich auf jedenfall noch aufhübschen :D.
Allgemein würde ich gerne ein paar Meinungen von euch hören, Kritiken kann ich vertragen :mrgreen:
Traue keinem Computer, den du nicht aus dem Fenster werfen kannst.
Xynon auf GitHub
Lasse
User
Beiträge: 112
Registriert: Donnerstag 3. Februar 2011, 18:25

Schon wieder ein Problem bei mir: :?
\levels.py", line 44, in parse
rect = pygame.Rect(map(int,node.get("rect", "0,0,0,0").split(",")))
TypeError: Argument must be rect style object
Xynon1
User
Beiträge: 1267
Registriert: Mittwoch 15. September 2010, 14:22

Hast du die aktuelle Version von dem Programm auf GitHub? und wann tritt der Fehler auf? Python3?, eventuell ist dort der Konstrucktor für Rect anders? oder die Leveldatei ist beschädigt.
Denn bei mir erscheint dieser nicht.
Traue keinem Computer, den du nicht aus dem Fenster werfen kannst.
Xynon auf GitHub
Antworten