Python Tutorial
- jetzt Python programmieren lernen

Animationen erstellen: Spielerfigur animieren über Sprite-Sheets in 2 verschiedenen Vorgehensweisen

„Was ist ein Sprite“ ist die erste logische Frage. Als englische Übersetzung taucht „Elf, Kobold“ auf. Das Sprite ist ein Grafikobjekt, dass über einen Hintergrund eingeblendet wird und ausgetauscht werden kann. Ursprünglich kommt die Bezeichnung daher, dass das Sprite nicht im Grafikspeicher zu finden war aber trotzdem über den Bildschirm „spuckt“. Anmerkung am Rande: Heutzutage mit der enormen Rechenkapazität findet es sich sehr wohl im Grafikspeicher.

Dieses Sprite wird in mehreren Varianten vorgehalten und wird dann je nach Zustand angezeigt. So können Bewegungen simuliert werden. Da unser Auge träge ist, müssen auch nicht alle zwischenschritte eine Bewegung gezeichnet werden.

Folgendes Beispiel werden wir Schritt für Schritt umsetzen:
Biene mit animierter Bewegung der Flügel

Für das Beispiel mit dem Flügelschlag der Biene reichen uns 6 Bilder, die sich abwechseln:

einzelne Bewegungsschritte unsere Biene im Flug

Die einzelnen Stadien der Bewegung kann man in einer Grafikdatei abspeichern und jeweils nur einen Ausschnitt davon anzeigen. Sind also mehrere Bewegungsschritte in einer Datei abgespeichert, spricht man von Sprite-Sheet (kennt man aus dem Englischen mit dem Begriff „data sheet“ für Datenblatt – anstelle von einzelnen Daten haben wir halt einzelne Grafiken in unserem Sprite-Sheet).

Wie können wir nun mit Python und Pygame daraus eine Animation erstellen? Sehr einfach und sogar auf 2 Wege, die hier beide gezeigt werden sollen.

Animation über Einzelgrafiken

Um das Beispiel nachzuvollziehen, können die einzelnen Grafiken von unserer bewegten Biene heruntergeladen werden unter:

Diese Grafiken speichern wir im Unterordner „bilder“ und laden diese über Pygane in eine Liste. Dadurch können wir dann im Spiel gezielt für die Animation die einzelnen Stadien der Bewegung über den Index auswählen.

Wir erstellen uns eine leere Liste für die Grafiken:

biene = ['','','','','','']

Und füllen nun diese:

biene = ['','','','','','']
biene[0] = pygame.image.load("bilder/biene-r-001.png")
biene[1] = pygame.image.load("bilder/biene-r-002.png")
biene[2] = pygame.image.load("bilder/biene-r-003.png")
biene[3] = pygame.image.load("bilder/biene-r-004.png")
biene[4] = pygame.image.load("bilder/biene-r-005.png")
biene[5] = pygame.image.load("bilder/biene-r-006.png")

Das ginge zwar als Code galanter, aber so ist es am einfachsten zu verstehen, was hier passiert.

Jetzt brauchen wir einen Status, welche Grafik aktuell angezeigt werden soll. Wir definieren eine Variable mit dem Namen frame = 0.

Und innerhalb unserer Hauptschleife laufen wir durch alle vorhandenen Framenummer durch und beginnen wieder bei 0, wenn wir den letzten erreicht haben. Noch schöner wäre, wenn wir die Frames einfach rückwärts wieder durchgehen würden.

    frame += 1

    if frame > 5:
        frame = 0

Und nun müssen wir nur noch unsere Biene mit dem entsprechenden Index (sprich Frame) zeichnen:

    fenster.blit(biene[frame], (10, 10))

Unsere Biene ist nun wild am Flügelschlagen (man will ja auch vorwärts kommen im Leben).

Biene mit animierter Bewegung der Flügel
Biene mit animierter Bewegung der Flügel

Und hier nun der komplette Code:

# Importieren u. initialisieren der Pygame-Bibliothek
import pygame
from pygame.locals import *
pygame.init()

# Variablen/KONSTANTEN setzen
W, H = 800, 600
FPS  = 30
SCHWARZ = ( 0, 0, 0)
WEISS   = ( 255, 255, 255)
GRAU    = ( 155, 155, 155)
spielaktiv = True

biene = ['','','','','','']
biene[0] = pygame.image.load("bilder/biene-r-001.png")
biene[1] = pygame.image.load("bilder/biene-r-002.png")
biene[2] = pygame.image.load("bilder/biene-r-003.png")
biene[3] = pygame.image.load("bilder/biene-r-004.png")
biene[4] = pygame.image.load("bilder/biene-r-005.png")
biene[5] = pygame.image.load("bilder/biene-r-006.png")

frame = 0 

# Definieren und Öffnen eines neuen Fensters
fenster = pygame.display.set_mode((W, H))
pygame.display.set_caption("python-lernen.de - Sprite (mehrere Grafiken) animieren")
clock = pygame.time.Clock()

# Schleife Hauptprogramm
while spielaktiv:
    # Überprüfen, ob Nutzer eine Aktion durchgeführt hat
    for event in pygame.event.get():
        # Beenden bei [ESC] oder [X]
        if event.type==QUIT or (event.type==KEYDOWN and event.key==K_ESCAPE):
            spielaktiv = False

    # Spiellogik

    # Spielfeld löschen
    fenster.fill(GRAU)

    # Spielfeld/figuren zeichnen
    frame += 1

    if frame > 5:
        frame = 0

    fenster.blit(biene[frame], (10, 10))

    # Fenster aktualisieren
    pygame.display.flip()
    clock.tick(FPS)

Falls man sich die Bewegung langsam ansehen möchten, kann man einfach den FPS-Wert umstellen auf: FPS = 1

Animation über ein Sprite-Sheet (alle Grafiken in nur einer Datei)

Der große Unterschied ist, dass wir nun nicht zig Einzeldateien haben, sondern eine große Datei, in der alle Bewegungsstadien enthalten sind.

Zum besseren verdeutlichen ist um jedes Stadium ein bunter Rahmen gezogen:

die 6 Stadien des Fluges unserer Biene
die 6 Stadien des Fluges unserer Biene

Was können wir nun damit anfangen?

Jedes Bild unserer Bienen ist 100 Pixel breit und 100 Pixel hoch.

Aufbau eines Sprite-Sheets mit Maßen
Aufbau eines Sprite-Sheets mit Maßen

Somit können wir für jedes Stadium exakt die Angaben machen, bei welchem X- und Y-Wert das entsprechende Teilstück des Bildes anfängt und auch aufhört.

Wir erhalten also 4 Werte. Wollen wir beispielsweise das dritte Stadium nutzen (die grün umrandete Biene), dann können wir dies direkt über die Werte (201, 0, 301, 100) ansprechen.

Bei der Anweisung blit() gibt es die Möglichkeit, dass nur ein Teilbereich des gesamten Bildes (also ein Ausschnitt) angezeigt wird. Dieser Ausschnitt wird festgelegt über den Startpunkt, also den oberen X- und Y-Wert und zusätzlich die Breite und die Höhe. Als Beispiel: der Teilausschnitt mit dem grünen Rahmen kann somit über die Angabe (201, 0, 100,100) ausgewählt werden.

Unser Code:

fenster.blit(GRAFIK, (POSITION X, Y), angezeigter TEILBEREICH)

oder mit Zahlen gefüllt – man achte auf die Klammern!

fenster.blit(biene, (20, 10), (201, 0, 100,100))

Unser Code unterscheidet sich also nicht so wesentlich wie in der ersten Vorgehensweise. Wir bauen im Folgenden nochmals das gleiche Beispiel wie schon in der Vorgehensweise mit den Einzelgrafiken – jetzt aber mit unserer Grafik als Sprite-Sheet.

Die Grafik kann zum Testen heruntergeladen werden unter:

https://www.python-lernen.de/bilder/biene-sprite-sheet.png
Bild mit allen Bewegungsstufen als Sprite-Sheet
(oder einfach auf die Grafik mit der rechten Maustaste klicken und "speichern unter" wählen)

Wir laden im Python-Code unsere Biene als Grafik:

biene = pygame.image.load("bilder/biene-sprite-sheet.png")

Und hinterlegen die Koordinaten unter bereich: X- und Y-Wert, wo der Bereich beginnt und die letzten beiden Zahlen sind die Breite und die Höhe (was in allen Fällen 100 Pixel sind).

bereich = ['','','','','','']
bereich[0] = (0,0,100,100)
bereich[1] = (101,0,100,100)
bereich[2] = (202,0,100,100)
bereich[3] = (303,0,100,100)
bereich[4] = (404,0,100,100)
bereich[5] = (505,0,100,100) 

Innerhalb unserer Hauptschleife ändern wir in jedem Durchgang die Frame-Nummer und lassen uns den durch den Bereich festgelegten Teilausschnitt ausgeben:

    # Spielfeld/figuren zeichnen
    frame += 1

    if frame > 5:
        frame = 0

    print(frame, bereich[frame])

    fenster.blit(biene, (240, 10), bereich[frame])

Als Ergebnis erhalten wir wieder unsere animierte fliegende Biene.

Der komplette Code:

# Importieren u. initialisieren der Pygame-Bibliothek
import pygame
from pygame.locals import *
pygame.init()

# Variablen/KONSTANTEN setzen
W, H = 800, 600
FPS  = 2
SCHWARZ = ( 0, 0, 0)
WEISS   = ( 255, 255, 255)
GRAU    = ( 155, 155, 155)
spielaktiv = True

biene = pygame.image.load("bilder/biene-sprite-sheet.png")

bereich = ['','','','','','']
bereich[0] = (0,0,100,100)
bereich[1] = (101,0,100,100)
bereich[2] = (202,0,100,100)
bereich[3] = (302,0,100,100)
bereich[4] = (402,0,100,100)
bereich[5] = (504,0,100,100)

print(bereich)

frame = 0 

# Definieren und Öffnen eines neuen Fensters
fenster = pygame.display.set_mode((W, H))
pygame.display.set_caption("python-lernen.de - Sprite-Sheet animieren")
clock = pygame.time.Clock()

# Schleife Hauptprogramm
while spielaktiv:
    # Überprüfen, ob Nutzer eine Aktion durchgeführt hat
    for event in pygame.event.get():
        # Beenden bei [ESC] oder [X]
        if event.type==QUIT or (event.type==KEYDOWN and event.key==K_ESCAPE):
            spielaktiv = False

    # Spiellogik

    # Spielfeld löschen
    fenster.fill(WEISS)

    # Spielfeld/figuren zeichnen
    frame += 1

    if frame > 5:
        frame = 0

    print(frame, bereich[frame])

    fenster.blit(biene, (240, 10), bereich[frame])

    # Fenster aktualisieren
    pygame.display.flip()
    clock.tick(FPS)

PS: die Sprünge bei den verschiedenen Bereichen kommen daher, dass die Grundgrafik nicht sauber ist – sprich nicht überall 100 Pixel Breite pro Biene haben (die Grafik mache ich bei Gelegenheit noch sauber). Wichtig ist hier erst einmal das Verständnis für die Vorgehensweise.

Aufgabe: Animation eines Pferdes

Es gibt eine sehr bekannte Fotografie eines laufenden Pferdes aus dem Jahr 1872 von Eadweard Muybridge. Aufgabe ist, dieses Foto aus Wikipedia zu laden und über die Sprite-Sheet-Technik animieren. Das Foto findet sich unter: https://en.wikipedia.org/wiki/Eadweard_Muybridge#/media/File:The_Horse_in_Motion_high_res.jpg

Viel Spaß bei der Umsetzung.