image image


Nature of Code mit der Python Arcade Library: Bouncing Ball

Ich habe es geahnt und Ihr hattet es sicher schon befürchtet: Mein Beitrag zur Python Arcade Bibliothek hat mir keine Ruhe gelassen. Und nachdem ich mir am Wochenende die Monster Playlist von Attila Toth reingezogen hatte, kam mir folgender, ketzerischer Gedanke: Arcade setzt auf Pyglet und damit auf OpenGL auf und besitzt so einen reichen Fundus graphischer Primitive, die ich bei Pygame Zero schmerzlich vermißt hatte, besonders fehlten mir Polygone und Dreiecke. Wie wäre es denn, wenn ich die Programme aus Daniel Shiffmans Buch »The Nature of Code« nicht von Processing (Java) nach Pygame Zero, sondern mithilfe der Arcade-Bibliothek nach Python portieren würde? So schwer kann das doch nicht sein.

image

Gesagt, getan. Ich habe mir das Bouncing-Ball-Programm aus dem ersten Kapitel vorgenommen, um es mit Vektoren in Arcade zu implementieren.

Dazu mußte ich erst einmal ein paar Importe vornehmen:

import arcade
import random
from pvector import PVector

Okay, wenn man einen Arcade-Sketch schreiben will, muß man natürlich die Bibliothek importieren, (Pseudo-) Zufallszahlen braucht man auch immer und da ich mit Vektoren arbeiten wollte, habe ich meine eigene PVector-Klasse ebenfalls importiert.

Dann habe ich ein paar Konstanten deklariert:

WIDTH = 400
HEIGHT = 400
TITLE = "Bouncing Ball"
NO_BALLS = 10

colorlist = [(239, 242, 63), (198, 102, 230), (151, 87, 165), (129, 122, 198), (98, 199, 119)]

Die colorlist ist wieder meine Coding Train Farbpalette, die ich als Reminiszenz an Daniel Shiffman verwende.

Dann habe ich die Klasse Ball implementiert. Sie besteht aus einem Konstruktor und zwei Methoden, mit denen ich on_draw() und on_update() (siehe weiter unten) gekapselt habe:

class Ball():
    
    def __init__(self):
        self.radius = random.randrange(5, 20)
        # Position and Velocity
        x = random.randrange(self.radius, WIDTH - self.radius)
        y = random.randrange(self.radius, HEIGHT - self.radius)
        self.position = PVector(x, y)
        v_x = random.randrange(-10, 10)
        v_y = random.randrange(-10, 10)
        self.velocity = PVector(v_x, v_y)
        # Farbe
        self.color = random.choice(colorlist)
    
    def show(self):
        arcade.draw_circle_filled(self.position.x, self.position.y, self.radius, self.color)
        arcade.draw_circle_outline(self.position.x, self.position.y, self.radius, arcade.color.BLACK)
    
    def move(self):
        self.position.add(self.velocity)
    
        if (self.position.x > WIDTH - self.radius) or (self.position.x < self.radius):
            self.velocity.x *= -1
        if (self.position.y > HEIGHT - self.radius) or (self.position.y < self.radius):
            self.velocity.y *= -1

Im Konstruktor wird der Ball erzeugt und bekommt einen zufälligen Durchmesser, eine zufällige Position innerhalb des Fensters, eine zufällige Geschwindigkeit und eine zufällige Farbe aus der Coding-Train-Farbpalette zugewiesen. Die show()-Methode zeichnet den Kreis dann an seiner momentanen Position. Dabei habe ich wieder den Trick verwandt, daß ich zuerst einen gefüllten Kreis zeichnen und danach eine schwarze Outline darüberlege.

Die Methode move() addiert vektoriell die Geschwindigkeit zur Position, wodurch der Ball eine neue Position erhält. Die restlichen Zeilen sind einfach die Randbehandlung, die den Ball an den Rändern des Fensters abprallen läßt.

Die Klasse BouncingBall enthält das eigentliche Spiel. Sie erbt von arcade.Window. Sie erzeugt das Spielefenster und muß die Methoden on_draw() und on_update() implementieren. Die on_update()-Methode wird, falls man nicht delta_time überschreibt, von Arcade etwa 60 Mal in der Sekunde aufgerufen und stößt dann, falls es etwas neu zu zeichnen gibt, die on_draw()-Methode an. on_draw() muß zwingend als erstes arcade.start_render() aufrufen. Die Klasse sieht bei mir daher so aus:

class BouncingBall(arcade.Window):
    
    def __init__(self):
        super().__init__(WIDTH, HEIGHT, TITLE)
        arcade.set_background_color(((149, 224, 245)))
        self.balls = []
        for _ in range(NO_BALLS):
            self.balls.append(Ball())
    
    def on_draw(self):
        arcade.start_render()
        
        for ball in self.balls:
            ball.show()
    
    def on_update(self, delta_time):
        
        for ball in self.balls:
            ball.move()

Mit dieser Logik ähnelt die Arcade-Bibliothek eher Processing, denn anderen, klassischen Spiele-Bibliotheken, in denen der Programmierer die Spieleschleife selber erzeugen muß. Der Konstruktor ist so etwas wie die setup()-Methode in Processing und on_update() mit on_draw() sind in etwa das, was die draw()-Methode in Processing ist.

Jetzt fehlen nur noch zwei Zeilen, um das Skript fertigzustellen:

BouncingBall()
arcade.run()

BouncingBall() erzeugt das Spielefenster und arcade.run() sorgt für die Spieleschleife. Beendet wird das Skript – falls man nichts anderes programmiert hat – mit einem Klick in den Schließknopf des Fensters.

Den kompletten Quellcode – inklusive der PVector-Klasse – findet Ihr in meinem GitHub-Repositorium.

Ich habe mit diesem Skript nur an der Oberfläche dessen gekratzt, was mit der Arcade-Bibliothek möglich ist. Aber es hat Spaß gemacht, damit zu spielen und daher werde ich Euch vermutlich in Zukunft mit weiteren Python-Arcade-Skripten behelligen. 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 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