Pyxel und Paletten: Pyxel-Tutorial Stage 4

Pyxel
Python
Retrogaming
Spieleprogrammierung
Autor:in

Jörg Kantel

Veröffentlichungsdatum

17. April 2025

Auf meiner Entdeckungsreise durch Pyxel, der kleinen (Python3-) Retrogame-Engine, bin ich wieder ein Stück vorangekommen: Mir ist es gelungen, dem Teil andere als die Default-Farbpalette unterzujubeln.

Pyxel Default-Farbpalette

Pyxel Default-Farbpalette

Pyxel benutzt von Haus aus eine eher aus 16 gedeckten Farben bestehende Palette, die zwar einen guten Kompromis bildet, aber maches Mal möchte man doch auch andere Farben benutzen können. Dazu besitzt der Pyxel-Editor einen recht einfachen Mechanismus: Wenn in dem Verzeichnis, in dem die Ressourcendatei (.pyxres) liegt, eine gleichnamige Datei mit einer Farbpalette (.pyxpal) abgelegt wird, wird diese von der Ressourcendatei gelesen und die (16!) Farben aus dieser Datei werden übernommen. Diese Palettendatei enthält hexadezimale Einträge für die Anzeigefarben (zum Beispiel 1100ff), getrennt durch Zeilenumbrüche.

Ich habe in einem ersten Versuch die Standard-Farbpalette der Retro-Fantasy-Konsole TIC-80, die den schönen Namen Sweety 16 trägt, übernommen, da sie mehr Grüntöne für eine Wald- und Wiesenlandschaft (zum Beispiel für ein Zelda-ähnliches Spiel (in der frühen Fassung)) besitzt.

TIC-80-Farbpalette (Sweety 16)

TIC-80-Farbpalette (Sweety 16)

Man sieht die Farben in der Leiste unten links. Werden sie beim ersten Aufruf des Editors nicht angzeigt, einfach den Editor noch einmal laden.

Zum Schluß habe ich dann auch noch die Default-Farbpalette für die (proprietäre) Fantasykonsole Pico-8 installiert, die kräftigere, leuchtende Farben aufweist.

Pico-8-Farbpalette

Pico-8-Farbpalette

Natürlich habe ich dann auch noch ein kleines Spiel programmiert, mit dem ich die Paletten testen konnte (einfach in der Zeile pyxel.load("assets/res.pyxres") die entsprechende Ressourcen-Datei laden):

import pyxel

# Ein paar nützliche Konstanten
TS = 8          # Tilesize
COLKEY = 0      # Color Key
WALLS = [(2, 1)]

def get_tile(tile_x, tile_y):
    # pyxel.tilemaps() gibt ein Tupel mit den x- und y-Koordinaten
    # aus der Tilemap des mit pget() identifizierten Tiles zurück
    return pyxel.tilemaps[0].pget(tile_x, tile_y)

class Player:

    def __init__(self, _x, _y):
        self.x = _x * TS
        self.y = _y * TS
        self.w = self.h = TS
        self.u = 0  # Die x-Position des Sprites in der Imagebank
        self.v = 0  # Die y-Position des Sprites in der Imagebank
        self.imagebank = 0
        self.dir = "right"

    def move(self):
        if (pyxel.btnp(pyxel.KEY_LEFT)
                and get_tile((self.x - TS)//TS, self.y//TS) not in WALLS):
            self.dir = "left"
            self.x -= TS
        elif (pyxel.btnp(pyxel.KEY_RIGHT)
                and get_tile((self.x + TS)//TS, self.y//TS) not in WALLS):
            self.dir = "right"
            self.x += TS
        if self.dir == "left":
            self.w = -TS
        else:
            self.w = TS

class App:

    def __init__(self):
        pyxel.init(32 * TS, 8 * TS, "Pyxel Tutorial Stage 4", display_scale=4)
        pyxel.load("assets/res.pyxres")

        # Initialisiere den Spieler
        # Position in Map-Koordinaten
        self.player = Player(1, 4)

    def run(self):
        pyxel.run(self.update, self.draw)

    def update(self):
        self.player.move()

    def draw(self):
        pyxel.cls(0)

        # Zeichen die Map
        pyxel.bltm(0, 0, 0, 0, 0, 32 * TS, 8 * TS, 0)

        # Zeichne den Player
        pyxel.blt(self.player.x, self.player.y, self.player.imagebank,
                  self.player.u, self.player.v, self.player.w, self.player.h,
                  COLKEY)

App().run()

Es passiert (noch) nicht viel neues, lediglich daß der Avatar beim Richtungswechsel auch gespiegelt wird (in die »richtige« Richtung schaut):

Wer weiß, vielleicht wage ich mich bei meinen nächsten Versuchen dann auch an ein »Zelda-style Dungeon« in Pyxel, wie es in dieser YouTube-Playlist der User Radical Slice für die Konsole Pico-8 vorgestellt hat. Still digging!