image image


image

Erste Schritte mit der Arcade Game Library und Python

Nachdem ich mich über die Osterfeiertage durch die Dokumentation der Arcade Game Library gewühlt hatte, wollte ich auch damit etwas anstellen, um dahinter zu kommen, wie sie eigentlich funktioniert. Daher habe ich mir erst einmal das »Starting Template« angeschaut und daraus ein kleines Testprogramm gebastelt.

Seltsam war für mich, daß alle Sprite-Listen und auch alle Sprites schon in der __init__()-Methode initialisiert und mit None vorbelegt werden sollen, wo es doch auch noch eine setup()-Methode gibt, die die eigentliche Initialisierung mit den »echten« Werten vornimmt. Aber da ich momentan noch nicht weiß, was Arcade eigentlich alles hinter den Kulissen anstellt, habe ich mich brav an die Vorgaben des Templates gehalten. In der setup()-Methode habe ich dann die Sprite-Listen und Sprites (und auch die Physics Engine) initialisiert:

    def setup(self):
        # Create the Sprite lists
        self.player_list = arcade.SpriteList()
        self.wall_list = arcade.SpriteList()
        
        # Set up the player
        alien_image = os.path.join(self.image_path, "alien.png")
        self.player_sprite = arcade.Sprite(alien_image)
        self.player_sprite.center_x = 200
        self.player_sprite.center_y = 300
        self.player_list.append(self.player_sprite)
        
        # Set up the crate
        wall = arcade.Sprite(os.path.join(self.image_path, "box_crate.png"))
        wall.center_x = 200
        wall.center_y = 150
        self.wall_list.append(wall)

        # Create the »physics engine«
        self.physics_engine = arcade.PhysicsEngineSimple(self.player_sprite, self.wall_list)

Es ist eine einfache Physics Engine, die aber recht zuverlässig die Kollisionen abfängt (im Falle dieses Beispiels die Kollision des Aliens mit dem Kasten – zur Zeit das einzige Element in der wall_list). Alle Elemente sollten Mitglieder einer Sprite List sein, da nur diese in der on_draw()-Methode gezeichnet werden:

    def on_draw(self):
        # This command should happen before we start drawing. It will clear
        # the screen to the background color, and erase what we drew last frame.
        arcade.start_render()
        
        # Call draw() on all your sprite lists below
        self.wall_list.draw()
        self.player_list.draw()

Wichtig bei der on_draw()-Methode ist der Befehl arcade.start_render(), denn dieser sorgt dafür, daß der vorherige Bildschirm gelöscht und neu mit der Hintergrundfarbe (oder dem Hintergrundbild?) gezeichnet wird.

Die on_update()-Methode benötigt zwingend eigentlich nur den Befehl physics_engine.update(), aber ich habe da noch einen Check eingebaut, ob das Alien den Rand des Fensters erreicht und was dann mit ihm geschehen soll (es soll am gegenüberliegenden Fensterrand wieder erscheinen):

    def on_update(self, delta_time):
        self.physics_engine.update()
        
        # Border checking
        if self.player_sprite.left >= SCREEN_WIDTH:
            self.player_sprite.right = 0
        elif self.player_sprite.right <= 0:
            self.player_sprite.left = SCREEN_WIDTH
        if self.player_sprite.bottom >= SCREEN_HEIGHT:
            self.player_sprite.top = 0
        elif self.player_sprite.top <= 0:
            self.player_sprite.bottom = SCREEN_HEIGHT

Damit nicht die eine Hälfte des Aliens noch am Bildrand klebt, während die andere Hälfte schon auf der gegenüberliegenden Seite auftaucht, habe ich mit die Variablen player_sprite.left, player_sprite.right, player_sprite.top und player_sprite.bottom abgefragt und dann das Gegenüber jeweils auf 0 gesetzt. Daneben können auch noch die Werte center_x und center_y abgefragt oder gesetzt werden, was zum Beispiel bei Rotationen sinnvoll ist.

Eine Interaktion mit der Maus findet in diesem Beispielskript nicht satt, sondern nur die Interaktion mit der Tastatur wird abgefragt. Bei dem entsprechenden Tastendruck wird mit change_x oder change_y die Geschwindigkeit des Players auf den Wert player_speed oder, wenn die Taste wieder losgelassen wird, wieder zurück auf 0 gesetzt:

    def on_key_press(self, key, modifiers):
        if key == arcade.key.UP:
            self.player_sprite.change_y = self.player_speed
        elif key == arcade.key.DOWN:
            self.player_sprite.change_y = -self.player_speed
        elif key == arcade.key.LEFT:
            self.player_sprite.change_x = -self.player_speed
        elif key == arcade.key.RIGHT:
            self.player_sprite.change_x = self.player_speed
    
    def on_key_release(self, key, modifiers):
        if key == arcade.key.UP:
            self.player_sprite.change_y = 0
        elif key == arcade.key.DOWN:
            self.player_sprite.change_y = 0
        elif key == arcade.key.LEFT:
            self.player_sprite.change_x = 0
        elif key == arcade.key.RIGHT:
            self.player_sprite.change_x = 0

Das ist eigentlich schon alles. Das »Spiel« besteht aus einer Instanz der Klasse MyGame(), die zur Initialisierung nur noch die Methode setup() aufruft. Alles andere erledigt der Befehl arcade.run(), bei dem noch ziemlich viel hinter den Kulissen passiert. Aber in der Hauptsache organisiert er die Hauptschleife des Spiels, die laut Dokumentation etwa sechzig Mal in der Sekunde durchlaufen wird und die dabei die Methoden on_update() und on_draw() aufruft.

Da die Methode on_update() auch noch einen Parameter delta_time mitschleppt, dessen Bedeutung ich noch nicht kenne, nehme ich an, daß man hier auch irgendwie noch die Frame Rate manipulieren kann. Aber das muß ich erst noch herausfinden …

Für alle, die das Progrämmchen nachvollziehen wollen, hier noch einmal der volltändige Quellcode:

# Getting started with the Arcade Game Library
# Stage 1: Hello Alien
import arcade
import os

SCREEN_WIDTH = 400
SCREEN_HEIGHT = 400
SCREEN_TITLE = "👽 Hello Älien 👽"

class MyGame(arcade.Window):

    def __init__(self):
        super().__init__(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_TITLE)
        # Hier wird der Pfad zum Verzeichnis des ».py«-Files gesetzt
        file_path = os.path.dirname(os.path.abspath(__file__))
        self.image_path = os.path.join(file_path, "images")
        os.chdir(file_path)
        
        # If you have sprite lists, you should create them here,
        # and set them to None
        self.player_list = None
        self.wall_list = None
        self.player_speed = 5
        
        self.player_sprite = None
        
        arcade.set_background_color((0, 80, 125))

    def setup(self):
        # Create the Sprite lists
        self.player_list = arcade.SpriteList()
        self.wall_list = arcade.SpriteList()
        
        # Set up the player
        alien_image = os.path.join(self.image_path, "alien.png")
        self.player_sprite = arcade.Sprite(alien_image)
        self.player_sprite.center_x = 200
        self.player_sprite.center_y = 300
        self.player_list.append(self.player_sprite)
        
        # Set up the crate
        wall = arcade.Sprite(os.path.join(self.image_path, "box_crate.png"))
        wall.center_x = 200
        wall.center_y = 150
        self.wall_list.append(wall)

        # Create the »physics engine«
        self.physics_engine = arcade.PhysicsEngineSimple(self.player_sprite, self.wall_list)

    def on_draw(self):
        # This command should happen before we start drawing. It will clear
        # the screen to the background color, and erase what we drew last frame.
        arcade.start_render()
        
        # Call draw() on all your sprite lists below
        self.wall_list.draw()
        self.player_list.draw()

    def on_update(self, delta_time):
        self.physics_engine.update()
        
        # Border checking
        if self.player_sprite.left >= SCREEN_WIDTH:
            self.player_sprite.right = 0
        elif self.player_sprite.right <= 0:
            self.player_sprite.left = SCREEN_WIDTH
        if self.player_sprite.bottom >= SCREEN_HEIGHT:
            self.player_sprite.top = 0
        elif self.player_sprite.top <= 0:
            self.player_sprite.bottom = SCREEN_HEIGHT
            
    def on_key_press(self, key, modifiers):
        if key == arcade.key.UP:
            self.player_sprite.change_y = self.player_speed
        elif key == arcade.key.DOWN:
            self.player_sprite.change_y = -self.player_speed
        elif key == arcade.key.LEFT:
            self.player_sprite.change_x = -self.player_speed
        elif key == arcade.key.RIGHT:
            self.player_sprite.change_x = self.player_speed
    
    def on_key_release(self, key, modifiers):
        if key == arcade.key.UP:
            self.player_sprite.change_y = 0
        elif key == arcade.key.DOWN:
            self.player_sprite.change_y = 0
        elif key == arcade.key.LEFT:
            self.player_sprite.change_x = 0
        elif key == arcade.key.RIGHT:
            self.player_sprite.change_x = 0

game = MyGame()
game.setup()
arcade.run()
image image

Natürlich dürfen auch die beiden Bildchen nicht fehlen. Sie sind aus dem Platformer Pack Redux von Kenney.nl und stehen unter der CC0 1.0 Universal-Lizenz, können also ohne Probleme weiterverwendet werden.

Ich habe mittlerweile den Eindruck gewonnen, daß es sich lohnt, tiefer in die Geheimnisse der Arcade-Bibliothek einzutauchen. Wenn ich erst einmal herausbekommen habe, was die Bibliothek hinter den Kulissen wie abhandelt, scheint sie ein sehr mächtiges Werkzeug – nicht nur für die Spieleprogrammierung – zu sein. Und die Beschäftigung damit macht Spaß. Es werden daher in der nächsten Zeit sicher noch mehr kleinere Beispielprogramme hier auftauchen. 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