image image


image

Zu viele Äpfel – ein neues Spiel mit TigerJython und GameGrid

Oops, I did it again. Ich kann momentan von TigerJython und der GameGrid-Bibliothek nicht lassen. Daher habe ich mich an ein neues Spiel gewagt, in dem es Äpfel regnet. Der Spieler, symbolisiert durch eine kleine Spielekonsole, muß die grünen Äpfel fangen, um Punkte zu kassieren. Jedoch regnet es auch rote Äpfel. Und rote Äpfel sind tödlich – wie wir alle aus Schneewittchen wissen. Also: Jede Berührung mit einem grünen Apfel bringt einen Punkt, wird der Spieler jedoch von einem roten Apfel getroffen, ist das Spiel zu Ende.

Zur Realisierung: Die eigentliche Spielmechanik findet in der collide()-Methode der Klasse Player statt. Denn dort werden die Kollisionen registriert und die entsprechenden Aktionen ausgelöst:

    def collide(self, actor1, actor2):
        if actor2.__class__.__name__ == "GreenApple":
            win.removeActor(actor2)
            self.score += 1
            setStatusText("Punkte: " + str(self.score))
        elif actor2.__class__.__name__ == "RedApple":
            win.removeActor(actor2)
            self.hide()
            win.refresh()
            win.doPause()
        return(0)

Ich vermute mal, daß es (mindestens) eine elegantere Methode gibt, als if actor2.__class__.__name__ == "GreenApple", um herauszufinden, wer mir wem kollidierte, aber ich habe sie nicht gefunden und meine etwas brutale Lösung tut es auch. Und falls sich jemand über das win.refresh() wundert, das steht da nur, um nach Spielende einen Screenshot mit dem Sprite des Spielers zu bekommen. 🤓

Die Interaktion des Spielers mit seiner Spielfigur findet über die Funktion onKeyPressed() statt, die natürlich vorher mit addKeyRepeatListener(onKeyPressed) registriert werden muß:

def onKeyPressed(keyCode):
    xpos = player.getX()
    if keyCode == 37:   #left
        player.timer -= 1
        if player.timer == 0:
            player.showNextSprite()
            player.timer = 5
        player.setHorzMirror(True)
        if xpos > 20:
            player.setX(xpos - player.speed)
    elif keyCode == 39: #right
        player.setHorzMirror(False)
        player.timer -= 1
        if player.timer == 0:
            player.showNextSprite()
            player.timer = 5
        if xpos < (WIDTH - 20):           
            player.setX(xpos + player.speed)

Die Spielfigur besitzt zwei Sprites, die – gesteuert über den Timer – etwa alle zehn Millisekunden ausgetauscht werden. Die Methode setHorzMirror() gehört der Superklasse Actor und spiegelt die Sprites horizontal, so daß ein Spritepaar für beide Bewegungsrichtungen ausreicht.

Die Äpfel fallen mit unterschiedlichen Geschwindigkeiten, da ihnen bei der Initialisierung wie auch beim Wiedereintritt in das Spielfeld mit

speed = randint(2, 6)

immer wieder eine neue, zufällige Geschwindigkeit zugewiesen wird. Ja ich weiß, daß dies gegen die Gesetze des freien Falls verstößt, aber in meiner Spielewelt gibt es weder Galilei noch Newton und daher sind weder die Fallgesetze noch das Gravitationsgesetz dort bekannt.

Um die erreichten Punkte anzuzeigen, habe ich eine Statuszeile hinzugefügt. Der Befehl dazu heißt

win.addStatusBar(30)

und damit die Statuszeile dem Spielefenster hinzugefügt werden kann, muß das Fenster mit makeGameGrid() initialisiert werden, nur GameGrid() gibt eine Fehlermeldung.

So, nun wie immer den vollständigen Quellcode (den Ihr natürlich inklusive der Assets auch in meinem GitLab-Repositorium findet), damit Ihr das Spiel nachvollziehen und -programmieren könnt:

from gamegrid import *
from random import randint

WIDTH = 640
HEIGHT = 420

dt = 20  # delta time
numGreenApples = 100
numRedApples = 10

class Player(Actor):
    
    def __init__(self):
        Actor.__init__(self, True, "images/player.png", 2)
        self.speed = 3
        self.timer = 5
        self.score = 0
     
    def collide(self, actor1, actor2):
        if actor2.__class__.__name__ == "GreenApple":
            win.removeActor(actor2)
            self.score += 1
            setStatusText("Punkte: " + str(self.score))
        elif actor2.__class__.__name__ == "RedApple":
            win.removeActor(actor2)
            self.hide()
            win.refresh()
            win.doPause()
        return(0)

class GreenApple(Actor):
    
    def __init__(self):
        Actor.__init__(self, "images/applegreen.png")
        self.speed = 3
    
    def act(self):
        ypos = self.getY() + self.speed
        self.setY(ypos)
        if ypos > (HEIGHT - 32):
            self.setY(randint(-HEIGHT,  -20))
            self.setX(randint(20, WIDTH - 20))
            self.speed = randint(2, 6)

class RedApple(Actor):
    
    def __init__(self):
        Actor.__init__(self, "images/applered.png")
        self.speed = 3
    
    def act(self):
        ypos = self.getY() + self.speed
        self.setY(ypos)
        if ypos > (HEIGHT - 32):
            self.setY(randint(-HEIGHT,  -20))
            self.setX(randint(20, WIDTH - 20))
            self.speed = randint(2, 6)        
        
def onKeyPressed(keyCode):
    xpos = player.getX()
    if keyCode == 37:   #left
        player.timer -= 1
        if player.timer == 0:
            player.showNextSprite()
            player.timer = 5
        player.setHorzMirror(True)
        if xpos > 20:
            player.setX(xpos - player.speed)
    elif keyCode == 39: #right
        player.setHorzMirror(False)
        player.timer -= 1
        if player.timer == 0:
            player.showNextSprite()
            player.timer = 5
        if xpos < (WIDTH - 20):           
            player.setX(xpos + player.speed)

win = makeGameGrid(WIDTH, HEIGHT, 1, None, "images/background.png", False)
win.setBgColor(105, 210, 232)
win.setTitle(u"Zu viele Äpfel")
win.addStatusBar(30)

player = Player()
win.addActor(player, Location(WIDTH//2, HEIGHT - 55))
player.show(1)
win.addKeyRepeatListener(onKeyPressed)

for _ in range(numGreenApples):
    greenApple = GreenApple()
    greenApple.speed = randint(2, 6)
    player.addCollisionActor(greenApple)
    win.addActor(greenApple, Location(randint(20, WIDTH - 20), randint(-HEIGHT, -20)))

for _ in range(numRedApples):
    redApple = RedApple()
    redApple.speed = randint(2, 6)
    player.addCollisionActor(redApple)
    win.addActor(redApple, Location(randint(20, WIDTH - 20), randint(-HEIGHT, -20)))

win.setSimulationPeriod(dt)
win.show()
win.doRun()

Ich weiß nicht, ob das Spiel zu gewinnen ist, ich bin ein zu schlechter Spieler, um alle 100 grünen Äpfel einzufangen. Viel mehr als die im Screenshot angezeigten 67 Äpfel/Punkte habe ich bisher noch nicht geschafft. Von da an wird es nämlich richtig schwierig, weil die grünen Äpfel, die man einfangen muß, ja immer weniger werden, während die Zahl der gefährlichen roten Äpfel konstant bleibt. Daher habe ich (noch) keine Gewinnbehandlung implementiert, das Spiel ist einfach zu Ende und gewonnen, wenn man alle 100 Äpfel (gleich 100 Punkte) eingefangen hat.

Die Spielfigur wie auch das Tile für den Fußboden stammen aus dem freien (CC0) »Simplified Platformer Pack« von Kenney.nl und die Bilder der Äpfel habe ich den ebenfalls freien (CC-BY 4.0) »Twemojis« von Twitter entnommen. Zumindest die letzte Lizenz verlangt aber eine Namensnennung des Urhebers, dem bin ich hiermit nachgekommen.


(Kommentieren) 

image image



Ü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

Diese Spalte wurde absichtlich leergelassen!


Werbung


image  image  image
image  image  image


image