Auch wenn das Buch »Code the Classics Volume 1« nach mehr als drei Wochen immer noch nicht bei mir eingetroffen ist, habe ich mein Interesse an Pygame Zero immer noch nicht verloren. Um die Wartezeit zu überbrücken, habe ich mit der Programmierung eines Roguelikes begonnen. Es soll kein vollständiges Spiel werden, sondern nur die grundlegenden Mechaniken zeigen und prüfen, ob so etwas in Pygame Zero leicht zu implementieren ist.
Pygame Zero hält eine gedrückte Taste für eine gedrückte Taste und führt daher die damit ausgelösten Bewegungen immer wieder aus, sechzig Mal in der Sekunde. Daher waren die boolschen Variablen
hero_walking = True enemy_walking = False
notwendig, die nach einer Bewegung des Helden und seines Gegners (seiner Gegner) sofort auf False
gesetzt werden müssen. Denn Roguelikes sind rundenbasierte Spiele, sie funktionieren fast so wie ein Schachspiel. Der Held setzt einen Zug, danach sind die Gegner an der Reihe und dann darf der Held wieder ziehen. Pygame Zero bietet hierfür die Funktion on_key_up()
an:
def on_key_up(): global hero_walking, enemy_walking hero_walking = True enemy_walking = True
Hier werden erst wenn die Taste wieder losgelassen wird die beiden boolschen Variablen zurück auf True
gesetzt.
Wo ich ich schon einmal dabei war, habe ich auch gleich die Funktion on_key_down()
genutzt,
def on_key_down(): if keyboard.escape: sys.exit()
denn ich beende ein Spiel lieber mit der Escape
-Taste als mit einem Mausklick in den Schließknopf des Fensters. Außerdem bin ich dieses Verhalten von Pygame gewohnt und es ist mir unverständlcih, warum die Macher von Pygame Zero es nicht als Default-Verhalten implementiert haben.
Die anderen Reaktionen auf Tastendruck habe ich aus Symmetriegründen in die Funktion hero_move()
gesteckt, weil ich auch eine Funktion enemy_move()
implementiert hatte:
def hero_move(): global hero_walking old_hero_x = hero.x old_hero_y = hero.y if keyboard.left: if hero_walking: hero.x -= TILESIZE hero_walking = False if keyboard.right: if hero_walking: hero.x += TILESIZE hero_walking = False if keyboard.up: if hero_walking: hero.y -= TILESIZE hero_walking = False if keyboard.down: if hero_walking: hero.y += TILESIZE hero_walking = False
Der Gegner ist der zappelige Hulk, weil seine Bewegungen etwas hektisch und zappelig wirken und weil er ein grünes Monster ist. Wenn der Mindestabstand zwischen dem Helden und dem Monster eine gewisse Distanz unterschritten hat, versucht der zappelige Hulk dem Helden zu folgen, andernfalls zappelt er hin und her.
def enemy_move(): global enemy_walking old_enemy_x = enemy.x old_enemy_y = enemy.y if enemy.distance_to(hero) < MAXDIST: if enemy.x > hero.x and enemy_walking: enemy.x -= TILESIZE enemy_walking = False elif enemy.x < hero.x and enemy_walking: enemy.x += TILESIZE enemy_walking = False if enemy.y > hero.y and enemy_walking: enemy.y -= TILESIZE enemy_walking = False elif enemy.y < hero.y and enemy_walking: enemy.y += TILESIZE enemy_walking = False elif enemy_walking: if randint(0, 10) > 8: enemy.y = choice([enemy.y + TILESIZE, enemy.y - TILESIZE]) else: enemy.x = choice([enemy.x + TILESIZE, enemy.x - TILESIZE]) enemy_walking = False
Das sind die Hauptbestandteile meines kleinen Experiments. Das vollständige Programm sieht so aus:
import pgzrun from random import choice, randint import sys WIDTH = 640 HEIGHT = 480 TITLE = "Rogue 1" TILESIZE = 32 HTILES = 20 VTILES = 15 MAXDIST = 5*TILESIZE LEVEL_1 = [ "####################", "#@ # #", "# # ## #### #", "# # # #", "# # #### #", "##### # # #", "# # #### #", "# ##### #", "# E#", "# ################", "# #", "######### ### #", "# # #", "# # #", "####################" ] hero_walking = True enemy_walking = False def legal_move(walls, actor): for wall in walls: if wall.colliderect(actor): return(True) ## Der Held hero = Actor("hero") def hero_move(): global hero_walking old_hero_x = hero.x old_hero_y = hero.y if keyboard.left: if hero_walking: hero.x -= TILESIZE hero_walking = False if keyboard.right: if hero_walking: hero.x += TILESIZE hero_walking = False if keyboard.up: if hero_walking: hero.y -= TILESIZE hero_walking = False if keyboard.down: if hero_walking: hero.y += TILESIZE hero_walking = False ## Kollision mit Wall if legal_move(walls, hero): hero.x = old_hero_x hero.y = old_hero_y def reset_hero(x, y): hero.topleft = (x*TILESIZE, y*TILESIZE) ## Der Feind enemy = Actor("enemy") def enemy_move(): global enemy_walking old_enemy_x = enemy.x old_enemy_y = enemy.y if enemy.distance_to(hero) < MAXDIST: if enemy.x > hero.x and enemy_walking: enemy.x -= TILESIZE enemy_walking = False elif enemy.x < hero.x and enemy_walking: enemy.x += TILESIZE enemy_walking = False if enemy.y > hero.y and enemy_walking: enemy.y -= TILESIZE enemy_walking = False elif enemy.y < hero.y and enemy_walking: enemy.y += TILESIZE enemy_walking = False elif enemy_walking: if randint(0, 10) > 8: enemy.y = choice([enemy.y + TILESIZE, enemy.y - TILESIZE]) else: enemy.x = choice([enemy.x + TILESIZE, enemy.x - TILESIZE]) enemy_walking = False ## Kollision mit Wall if legal_move(walls, enemy): enemy.x = old_enemy_x enemy.y = old_enemy_y ## User Input def on_key_down(): ## Spielende mit ESC if keyboard.escape: sys.exit() def on_key_up(): global hero_walking, enemy_walking hero_walking = True enemy_walking = True ## Level walls = [] def setup_maze(level): for y in range (len(level)): for x in range (len(level[y])): sprite = level[y][x] if sprite == "#": wall = Actor("wall") wall.topleft = (x*TILESIZE, y*TILESIZE) walls.append(wall) if sprite == "@": hero.topleft = (x*TILESIZE, y*TILESIZE) if sprite == "E": enemy.topleft = (x*TILESIZE, y*TILESIZE) ## Das Spiel setup_maze(LEVEL_1) def draw(): screen.fill((128, 128, 130)) for wall in walls: wall.draw() enemy.draw() hero.draw() def update(): hero_move() enemy_move() if enemy.colliderect(hero): reset_hero(1, 1) pgzrun.go()
Natürlich findet Ihr den kompletten Sourcecode und die verwendeten Assets in meinem GitHub-Repositorium. Die Sprites und die Mauerteile habe ich dem freien (CC BY 3.0) Tilesets von TomeTik entnommen.
Jetzt müßt Ihr mir nur noch die Daumen drücken, daß »Code the Classics Volume 1« bald bei mir eintrifft. Denn das PDF, das man kostenlos herunterladen kann, ist doch recht mühselig zu lesen (ich müßte es ausdrucken) und ich habe große Lust, mit Pygame Zero noch mehr anzustellen.
Ü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