Nach meinem Rant letzte Woche über fehlende Tutorials zur objektorientierten Programmierung in Pygame Zero dachte ich mir, daß ich doch mit gutem Beispiel vorangehen und selber einmal ein komplettes Spielchen objektorientiert in Pygame Zero programmieren könnte.
Gedacht, getan: Ich habe mir den Basic Side Scroller, den ich vor einigen Wochen in Processing.py, dem Python-Mode von Processing programmiert hatte (Teil 1, Teil 2) vorgenommen und ihn ein wenig aufgebohrt. Zum einen habe ich die Hintergrundbilder nicht mehr aus Kreisen zusammengesetzt, sondern mir auf OpenGameArt.org diese freien Bilder von GrumpyDiamond heruntergeladen und sie mit einem Bildverarbeitungsprogramm meines Vertrauens aufgehübscht. Die Hindernisse und das hüpfende Alien stammen wieder aus dem schier unerschöpflichen Fundes von Kenney.nl. Auch diese mußte ich ein wenig nachbearbeiten, weil sonst das umgebende Rechteck für die Kollisionserkennung zu groß gewesen wäre.
Zum anderen besitzt das Programm nun drei Basis-Klassen (Layer
, Obstacle
und Player
), die alle von Actor
abgeleitet wurden. Die Trennung zwischen Layer
und Obstacle
wäre nicht unbedingt erforderlich gewesen, aber in meinen Augen schien sie irgendwie logisch.
Neben den Klassendefinitionen nehmen den größten Teil des Programms die Erzeugung der einzelnen Instanzen ein, insbesondere, da die »beweglichen« Layer immer zwei Instanzen benötigten, damit das zweite Bild nahtlos an das erste Bild anschließen kann. Danach habe ich zwei Listen engelegt (layers
und obstacles
), die dann in der update()
-Funktion des Hauptprgramms abgearbeitet werden:
def update(): for layer in layers: layer.move() alien.move() for obstacle in obstacles: if alien.colliderect(obstacle): alien.score -= 1
Der draw()
-Funktion habe ich noch eine Anzeige spendiert, die den Punktestand angibt.
def draw(): for layer in layers: layer.show() alien.show() screen.draw.textbox("Score: " + str(alien.score), (0, 440, 100, 20))
Ich bin kein guter Spieler, daher habe ich es mir einfach gemacht und jeden erfolgreichen Sprung mit einem Punkt belohnt, während jeder Mißerfolg mit Punkteabzug bestraft wird (da das Alien durchaus mehrfach mit den Hindernissen kollidieren kann, kann der Punktabzug ziemlich heftig ausfallen). Hier ist sicher noch Optimierungsbedarf, aber für ein einfaches Beispiel reicht es erst einmal aus.
Für diejenigen unter Euch, die das Spiel nachprogrammieren oder eventuell sogar verbessern wollen, hier der komplette Quellcode:
import pgzrun class Layer(Actor): def __init__(self, image): Actor.__init__(self, image) self.speed = 0 self.turnvalue = 0 def move(self): self.left -= self.speed if self.right <= 0: self.left = self.turnvalue def show(self): self.draw() class Obstacle(Actor): def __init__(self, image, pos): Actor.__init__(self, image, pos) self.bottomleft = pos self.speed = 4 def move(self): self.left -= self.speed if self.right <= 0: self.left = 3.4*WIDTH def show(self): self.draw() class Player(Actor): def __init__(self, image, pos): Actor.__init__(self, image, pos) self.pos = pos self.status = "walking" self.hit = False self.count = 0 self.vely = 0 self.score = 0 self.speed = 1 def move(self): if self.status == "walking": self.count += self.speed if self.count > 10: self.count = 0 if self.count < 6: self.image = "alienwalk1.png" else: self.image = "alienwalk2.png" if self.status == "jumping": self.image = "alienjump.png" self.bottom += self.vely self.vely += 0.1 if self.bottom >= HEIGHT - 75: self.bottom = HEIGHT - 75 self.vely = 0 self.status = "walking" self.score += 1 def show(self): self.draw() WIDTH = 720 HEIGHT = 480 TITLE = "Jump, Älly, Jump!" bg = Layer("sky_background") bg.topleft = 0, 0 bg.turnvalue = 0 sun = Layer("sun") sun.topleft = 500, 20 sun.turnvalue = 0 clouds = Layer("clouds_all") clouds.topleft = WIDTH, 0 clouds.speed = 1 clouds.turnvalue = WIDTH mountain1 = Layer("mountain_full") mountain1.bottomleft = 0, HEIGHT - 75 mountain1.speed = 2 mountain1.turnvalue = 2*WIDTH mountain2 = Layer("mountain_full") mountain2.bottomleft = 1279, HEIGHT - 75 mountain2.speed = 2 mountain2.turnvalue = 2*WIDTH ground1 = Layer("ground") ground1.bottomleft = 0, HEIGHT + 10 ground1.speed = 4 ground1.turnvalue = WIDTH ground2 = Layer("ground") ground2.bottomleft = 1270, HEIGHT + 10 ground2.speed = 4 ground2.turnvalue = WIDTH spikes1 = Obstacle("spikes", (WIDTH + 100, HEIGHT - 75)) cactus1 = Obstacle("cactus", (WIDTH + 600, HEIGHT - 75)) cactus2 = Obstacle("cactus", (WIDTH + 640, HEIGHT - 75)) cactus3 = Obstacle("cactus", (WIDTH + 670, HEIGHT - 75)) spikes2 = Obstacle("spikesbottomalt", (WIDTH + 1050, HEIGHT - 75)) spikes3 = Obstacle("spikesbottom", (WIDTH + 1150, HEIGHT - 75)) fence1 = Obstacle("fence", (WIDTH + 1620, HEIGHT - 75)) fence2 = Obstacle("fencebroken", (WIDTH + 1680, HEIGHT - 75)) fence3 = Obstacle("fence", (WIDTH + 1740, HEIGHT - 75)) layers = [bg, sun, clouds, mountain1, mountain2, ground1, ground2, spikes1, spikes2, spikes3, cactus1, cactus2, cactus3, fence1, fence2, fence3] obstacles = [spikes1, cactus1, cactus2, cactus3, spikes2, spikes3, fence1, fence2, fence3] alien = Player("alienwalk1", (50, HEIGHT - 115)) def on_key_down(): global alien_status, alien_vely if keyboard[keys.SPACE] and alien.status == "walking": alien.status = "jumping" alien.vely += -5 def update(): for layer in layers: layer.move() alien.move() for obstacle in obstacles: if alien.colliderect(obstacle): alien.score -= 1 def draw(): for layer in layers: layer.show() alien.show() screen.draw.textbox("Score: " + str(alien.score), (0, 440, 100, 20)) pgzrun.go()
Obwohl das Spiel sicher schon eine gewisse Komplexität aufweist, ist der Quellcode mit 141 Zeilen noch recht kurz geraten. Das ist eines der Vorteile von Pygame Zero, das vieles von dem, was in anderen Frameworks noch mühselig ausformuliert werden muß, automatisch im Hintergrund erledigt. Allerdings gibt man dafür auch einiges an Autonomie ab – etliche komplexere Aktionen, die Pygame selbstverständlich erlaubt, kann man in Pygame Zero nur mühsam oder gar nicht ausführen. Ich weiß momentan noch zu wenig über Pygame Zero, aber ich denke, man muß sich im Vorfeld schon überlegen, für welche Projekte man Pygame Zero einsetzt und für welche man doch lieber direkt auf Pygame zurückgreift.
Das Programm selber ist unter den Namen sidescroller2.py
in meinem GitLab-Repositorium zufinden. Im Verzeichnis images
findet Ihr dort auch sämtliche verwendeten Bilder.
In diesem Sinne: Happy Coding!
Über …
Der Schockwellenreiter ist seit dem 24. April 2000 das Weblog digitale Kritzelheft von Jörg Kantel (Neuköllner, EDV-Leiter Rentner, Autor, Netzaktivist und Hundesportler — Reihenfolge rein zufällig). Hier steht, was mir gefällt. Wem es nicht gefällt, der braucht ja nicht mitzulesen. Wer aber mitliest, ist herzlich willkommen und eingeladen, mitzudiskutieren!
Alle eigenen Inhalte des Schockwellenreiters stehen unter einer Creative-Commons-Lizenz, jedoch können fremde Inhalte (speziell Videos, Photos und sonstige Bilder) unter einer anderen Lizenz stehen.
Der Besuch dieser Webseite wird aktuell von der Piwik Webanalyse erfaßt. Hier können Sie der Erfassung widersprechen.
Diese Seite verwendet keine Cookies. Warum auch? Was allerdings die iframes
von Amazon, YouTube und Co. machen, entzieht sich meiner Kenntnis.
Werbung