image image


image

Jetzt mit Ballern und mit pösen Pizzas: Pizza Plane in Pygame Zero

Ich habe eine zweite Version meines Fliegerspiels in Pygame Zero fertiggestellt. Jetzt treten endlich nicht nur die namengebenden »pösen Pizzas« auf, sondern der Spieler als kleiner, roter Doppeldecker kann sie auch abschießen. Größte Änderung gegenüber der Vorversion ist aber, daß – bis auf den (immer noch endlos scrollenden) Hintergrund – alle Akteure nun eigene Klassen bekommen haben.

Das war eine (Design-) Entscheidung, die ich einmal wegen der geplanten Portierung dieses Spiels nach Py5 getroffen habe, denn Py5 kennt keine Klasse Actor(), die muß ich selber implementieren. Zum anderen wurde es mir aber auch langsam unheimlich und unübersichtlich, die Klasse Actor() zu überfrachten. Durch die Einführung der Unterklassen Plane() (für den Spieler/Doppeldecker), Pizza() (für die Gegner) und Missile() für die Waffe habe ich – glaube ich zumindestens – den Quellcode übersichtlicher gestaltet, denn die Methoden update() und draw() rufen jetzt nur noch die korrespondierenden Methoden der jeweiligen Unterklassen auf.

Lediglich für den Hintergrund habe ich auf eine Subklassierung verzichtet, da passiert so wenig, das wäre in meinen Augen ein Overkill geworden.

Die Subklasse Pizza() weist zwei Besonderheiten auf:

class Pizza(Actor):
    
    def __init__(self, x, y):
        Actor.__init__(self, "pizza", (x, y))
        self.width = 36
        self.height = 36
        self.speed = -randint(2, 5)
    
    def reset(self):
        self.x = randint(WIDTH + 50, WIDTH + 750)
        self.y = randint(self.height, HEIGHT - self.height)
        self.speed = -randint(2, 5)
    
    def update(self):
        if self.colliderect(missile) and missile.fire:
            self.reset()
            missile.fire = False
        self.x += self.speed
        if self.x <= -self.width:
            self.reset()        

Zum einen besitzt sie eine reset()-Methode, die jede Pizza, wenn sie den linken Bildschirmrand verlassen hat oder abgeschossen wurde, wieder rechts außen auf eine neue Position mit einer neuen Geschwindigkeit positioniert und sie damit erneut ins Spiel bringt.

Und dann benutzt sie die Methode colliderect(object). Pygame Zero hat die Rect-Klasse aus Pygame nativ eingebaut und damit kann man alle Methoden dieser Klasse auch in Pygame Zero direkt verwenden ohne Pygame separat importieren zu müssen. Das ist etwas, was ich natürlich bei meinem Port nach Py5 selber implementieren muß. Ich denke, daß dies Bestandteil der Actor()-Klasse werden sollte.

Die Klasse Missile() wiederum habe ich sehr einfach gehalten. Der Spieler kann immer nur ein Geschoß abfeuern und erst wenn dieses entweder am rechten Bildschirmrand verschwunden ist oder eine Pizza getroffen wurde, steht ihm wieder ein Geschoß zur Verfügung (Missile.fire = True/False). Daher setzt jede Pizza, wenn sie getroffen wird, neben ihrer Neupositionierung auch missile.fire = False.

Die Geschwindigkeit des Geschosses ist so hoch, daß dies keine Einschränkung in der Feuerkraft des Doppeldeckers bedeutet. Im Gegenteil, wäre ein Dauerfeuer möglich, wäre das Spiel mit Sicherheit zu einfach.

Nun wie immer der komplette Quellcode der aktuellen Fassung, damit Ihr alles nachvollziehen und nachprogrammieren könnt:

# Pizza Plane Stage 2 (Version Pygame Zero)
# Endless Scrolling Background
# Background Image: »PWL« (https://opengameart.org/content/seamless-desert-background-in-parts)
# Aeroplane: Tappy Plane, Kenney (https://www.kenney.nl/assets/tappy-plane)
# Pizzas: Twitter Twemoji (https://twemoji.twitter.com/)
import pgzrun
import sys
from random import randint

WIDTH = 720
HEIGHT = 480
TITLE = "Pizza Plane Stage 2 (mit Missile und pösen Pizzas)"

# Konstanten
BG_LEFT = WIDTH/2
BG_BOTTOM = HEIGHT/2
BG_WIDTH = 1067             # Breite des Hintergrundbildes
BG_WIDTH2   = 533           # BG_WIDTH//2 (abgerundet)
BACKGROUND = "desert"
NO_ENEMIES = 10
PLANE_X = 70                # X-Position des Fliegers (bleibt fest)

# Klassendefinitionen

class Plane(Actor):
    
    def __init__(self):
        Actor.__init__(self, "planered_0", (PLANE_X, 200))
        self.images = []
        for i in range(3):
            img = "planered_" + str(i)
            self.images.append(img)
        self.r = 0
        self.updown = 3
        self.dir = "NONE"
        
    def update(self):
        if self.dir == "NONE":
            self.y += 0
        elif self.dir == "UP":
            if self.y > 20:
                self.y -= self.updown
        elif self.dir == "DOWN":
            if self.y < HEIGHT - 20:
                self.y += self.updown
        self.image = self.images[int(self.r)]
        self.r += 0.2
        if self.r >= 3.0:
            self.r = 0

class Missile(Actor):
    
    def __init__(self):
        Actor.__init__(self, "laserred", (plane.x, plane.y))
        self.speed = 25
        self.fire = False
    
    def update(self):
        if not self.fire:
            self.pos = plane.x, plane.y
        else:
            self.x += self.speed
            if self.x >= WIDTH:
                self.fire = False
                
class Pizza(Actor):
    
    def __init__(self, x, y):
        Actor.__init__(self, "pizza", (x, y))
        self.width = 36
        self.height = 36
        self.speed = -randint(2, 5)
    
    def reset(self):
        self.x = randint(WIDTH + 50, WIDTH + 750)
        self.y = randint(self.height, HEIGHT - self.height)
        self.speed = -randint(2, 5)
    
    def update(self):
        if self.colliderect(missile) and missile.fire:
            self.reset()
            missile.fire = False
        self.x += self.speed
        if self.x <= -self.width:
            self.reset()        
    
# Init Game
# Hintergrund
backs = []
back0 = Actor(BACKGROUND, (BG_LEFT, BG_BOTTOM))
back1 = Actor(BACKGROUND, (BG_WIDTH + BG_LEFT, BG_BOTTOM))
backs = [back0, back1]
# Player (Flieger)
plane = Plane()
# Missile
missile = Missile()
pizzas = []
for _ in range(NO_ENEMIES):
    pizza = Pizza(randint(WIDTH + 50, WIDTH + 750), randint(36, HEIGHT - 36))
    pizzas.append(pizza)

def update():
    ## Background
    for back in backs:
        back.x -= 1          
        if back.x <= -BG_WIDTH2:
            back.x = BG_WIDTH + BG_WIDTH2
    ## Missile
    missile.update()
    ## Pizzas
    for pizza in pizzas:
        pizza.update()
    ## Flieger
    plane.update()
            
def draw():
    screen.fill("#94b0c2")  # Light gray
    for back in backs:
        back.draw()
    for pizza in pizzas:
        pizza.draw()
    missile.draw()
    plane.draw()

def on_key_down():
    ## Steuerung des Fliegers
    if keyboard.up:
        plane.dir = "UP"
    if keyboard.down:
        plane.dir = "DOWN"
    ## Feuern mit rechter Pfeiltaste
    if keyboard.right:
        # print("FIRE!")
        missile.fire = True
    ## Spielende mit ESC
    if keyboard.escape:
        print("Bye, Bye, Baby!")
        sys.exit()

def on_key_up():
    plane.dir = "NONE"
    
pgzrun.go()

Natürlich findet Ihr den Quellcode und die bisher verwendeten Assets auch in meinem GitHub-Repositorium zu Pygame Zero. Die Credits zu den Assets habe ich in den Kommentaren zu Beginn des Quellcodes untergebracht.

Damit ist das Spiel beinahe auf den Stand, den die TigerJython/GameGrid-Version hatte. Lediglich die Explosionen muß ich noch einbauen. Danach will ich noch eine Anzeige des Punktestandes implementieren und dem Spiel mit einer bösen Meloni einen Boß-Gegner spendieren. Doch damit ist dann genug der Anspielungen auf die aktuelle, politische Situation in Italien. Eventuell gibt es noch je einen Start- und einen Ende-Bildschirm und dann will ich mich an die Py5-Implementierung setzten. Still digging!


(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 ehemaliger 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