Animierte GIFs in Proceso

Proceso
Python
PyScript
Processing
Creative Coding
Spieleprogrammierung
Autor:in

Jörg Kantel

Veröffentlichungsdatum

8. September 2025

Gestern abend stolperte ich über dieses Video, in dem der User Kenney Yip Coding ein Entenjagdspiel in pure JavaScript und dem HTML Canvas programmierte. Das ist an sich noch nichts Besonderes, aber die Bilder der Enten, die er verwendete, waren animierte GIFs, und da stellte sich mir die Frage, ob das nicht auch in Python ginge. Die kurze Antwort ist: Py5 kann mit den animierten GIFs nichts anfangen, aber Proceso, die PyScript-Version von Processing und Python, kann es.

Für meine Versuche habe ich mir die Entenbildchen und das Hintergrundbild aus dem GitHub-Repositorium von KennyYip »ausgeborgt« und daraus ein kleines Skriptchen gebastelt, das zwei kleine Enten ziellos über den Monitor flattern lässt:

Wenn Ihr mit der Maus in das Fenster klickt, wird das Skript zurückgesetzt, soviel Interaktivität muß sein. 😎

Proceso, wie auch P5.js, behandelt animierte GIFs wie jedes andere Bild auch, so daß es in dem Skript eigentlich nichts neues zu entdecken gibt:

from proceso import Sketch
from random import randint

WIDTH, HEIGHT = 640, 338
DUCK_W, DUCK_H = 80, 78
START_X, START_Y = 10, 50
BOTTOM = 200

p5 = Sketch()

def preload():
    global bg, duck_r, duck_l
    bg = p5.load_image("data/duckhunt-bg.png")  # Load the images
    duck_r = p5.load_image("data/duck-right.gif")
    duck_l = p5.load_image("data/duck-left.gif")

ducks = []

def setup():
    p5.create_canvas(WIDTH, HEIGHT)
    reset()

def reset():
    ducks.append(Duck(randint(10, p5.width/2), randint(10, BOTTOM), "right"))
    ducks.append(Duck(randint(p5.width/2, p5.width - DUCK_W), randint(10, BOTTOM), "left"))
    
def draw():
    p5.image(bg, 0, 0)
    for duck in ducks:
        duck.update()
        duck.display()

def mouse_clicked():
    ducks.clear()
    reset()
    
class Duck():

    def __init__(self, _x, _y, _dir):
        self.pos = p5.Vector(_x, _y)
        self.vel = p5.Vector(randint(3, 5), randint(-2, 2))
        if _dir == "left":
            self.img = duck_l
            self.vel.x *= -1
        else:
            self.img = duck_r

    def update(self):
        self.pos += self.vel
        self.check_borders()

    def check_borders(self):
        if self.pos.x >= p5.width - DUCK_W:
            self.vel.x *= -1
            self.img = duck_l
        if self.pos.x <= 0:
            self.vel.x *= -1
            self.img = duck_r
        if self.pos.y <= 0 or self.pos.y >= BOTTOM:
            self.vel.y *= -1

    def display(self):
        p5.image(self.img, self.pos.x, self.pos.y, DUCK_W, DUCK_H)
        
p5.run_sketch(preload=preload, setup=setup, draw=draw, mouse_clicked=mouse_clicked)

Die von P5.js bekannte preload()-Funktion lädt die Bilder vor, so daß sie geladen sind, bevor setup() das eigentliche Skript startet.

Die Enten habe ich in die Klasse Duck() ausgelagert, wo ihre Position und ihr Geschwindigkeit (Velocity) durch Vektoren repräsentiert wird. Daher ruft die draw()-Funktion im Hauptprogramm eigentlich nur noch die Methoden update() und display() für die einzelnen Enten auf.

Ich bin mir nicht sicher, ob die Nutzung animierter GIFs in Spielen wirklich ein Fortschritt ist, Spielefiguren lassen sich in einer Einzelanimation (Frame bei Frame) meiner Meinung nach viel lebendiger gestalten. Aber »weil es geht« mußte schon so oft als Begründung herhalten und hier habe ich eben gezeigt, daß es geht.

Wie immer gibt es den Quellcode und die Assets nicht nur in meinem GitHub-Repositorium, sondern ich habe das Projekt auch auf meine PyScript-Seiten hochgeladen, wo Ihr es klonen und für eigene Experimente weiterentwickeln könnt.