HOWTO · Pygame
Kollisionen in Pygame erkennen
Dieses Tutorial diskutiert und stellt die verschiedenen Methoden vor, die wir für Kollisionstests oder Erkennung in Pygame verwenden können.
Auf dieser Seite
Welche Pygame-Kollisionsprüfung passt, hängt von den benötigten Formen und Ergebnissen ab. Mit collidepoint() prüfst du eine Position gegen ein Rechteck, mit colliderect() zwei Rechtecke und mit collidelist() oder collidedict() eine Sammlung. Bei Kreisen vergleichst du den Abstand ihrer Mittelpunkte mit der Summe ihrer Radien. Für unregelmäßige Sprites kombinierst du eine Rechteckprüfung als Grobfilter mit einer Maskenüberlappung. Die folgenden Beispiele erläutern das jeweilige API-Verhalten; sie sind keine vollständigen Spielschleifen. (collidelistall(); collidedictall(); pygame.mask.from_surface())
Eine passende Kollisionsprüfung auswählen
Wähle zunächst die kostengünstigste Prüfung, die zum Spielablauf passt. Rechtecke sind schnell und reichen für Plattformen, Wände und Hitboxen oft aus. Eine Punktprüfung eignet sich für die Auswahl mit der Maus. Mit Listen- und Dictionary-Methoden durchsuchst du viele Rechtecke und erhältst passende Positionen oder Schlüssel. Für runde Objekte eignet sich eine Kreisberechnung. Masken prüfen undurchsichtige Pixel und sind genauer, benötigen aber mehr Rechenaufwand.
pygame.Rect speichert Position und Größe eines Rechtecks. Die Kollisionsmethoden von Pygame melden eine geometrische Überlappung; sie bewegen keine Objekte und lösen keine Kollision auf. Verwende das Ergebnis, um festzulegen, was dein Spiel tun soll, etwa eine Bewegung stoppen, einen Gegenstand einsammeln oder einen Button öffnen.
Prüfen, ob ein Punkt in einem Rechteck liegt
Rufe rect.collidepoint(x, y) auf oder übergib die Koordinaten als einzelnes Tupel mit rect.collidepoint((x, y)). Die Methode liefert True, wenn der Punkt innerhalb des Rechtecks liegt, andernfalls False. Das ist beispielsweise für eine Mauszeigerprüfung nützlich: Übergib die aktuelle Mausposition und ändere das Aussehen des Buttons, wenn das Ergebnis wahr ist. Ein Punkt auf der rechten oder unteren Rechteckkante liegt außerhalb, da diese Kanten bei der Kollisionsgeometrie von Rect nicht dazugehören.
Prüfen, ob sich zwei Rechtecke überlappen
Erstelle zwei pygame.Rect-Objekte und rufe first.colliderect(second) auf. Die Methode gibt einen booleschen Wert zurück, den du direkt in einer if-Anweisung verwenden kannst. Zum Beispiel zeigt player_rect.colliderect(wall_rect), ob die Hitbox einer Spielfigur eine Wand berührt. Rechtecke, die sich nur entlang einer Kante berühren, überlappen sich nicht. Diese Prüfung ist schnell, doch eine rechteckige Hitbox kann auch transparente Bereiche eines Sprites umfassen.
Kollisionen in einer Rechteckliste finden
Verwende collidelist(rectangles), um ein Rechteck mit einer Folge von Rechtecken zu vergleichen und den Index des ersten Treffers zu erhalten. Gibt es keinen Treffer, lautet das Ergebnis -1. Wenn alle Trefferindizes wichtig sind, verwende collidelistall(rectangles); die Methode gibt eine Liste von Indizes zurück, die leer sein kann, wenn sich nichts überlappt. Die Indizes beziehen sich auf die ursprüngliche Folge. Mit ihnen kannst du daher das zugehörige Spielobjekt oder Rechteck abrufen. Weitere Informationen zu diesen Methoden und verwandtem Kollisionsverhalten findest du in der offiziellen Pygame-Rect-Dokumentation.
Wenn zum Beispiel player = pygame.Rect(10, 10, 20, 20) gilt und die Rechtecke an den Indizes 1 und 2 die Spielfigur überlappen, liefert player.collidelist(walls) den Wert 1, während player.collidelistall(walls) [1, 2] zurückgibt. Diese API-Aufrufe stehen als Inline-Beispiele im Text, weil beim Import von Pygame in der konfigurierten Laufzeit eine plattformspezifische Warnung ausgegeben wird. Aufrufe und Ergebnisse beruhen hier auf der dokumentierten API-Semantik und wurden nicht zur Laufzeit geprüft. So kannst du entweder nach einem Treffer abbrechen oder jede überlappende Wand untersuchen. Die Methoden liefern Positionen in der ursprünglichen Liste zurück, keine Sprite-Objekte.
Kollisionen in einem Rechteck-Dictionary finden
Verwende collidedict(rect_dict, use_values=True), um ein passendes Schlüssel-Rechteck-Paar zu erhalten. Gibt es keinen Treffer, lautet das Ergebnis None. Das Argument use_values=True ist erforderlich, wenn das Dictionary Rechtecke als Werte speichert. Ohne dieses Argument prüft die Methode die Schlüssel auf rechteckähnliche Werte und löst bei gewöhnlichen Zeichenkettenschlüsseln einen TypeError aus. Mit collidedictall(rect_dict, use_values=True) erhältst du alle passenden Schlüssel-Rechteck-Paare. Das ist praktisch, wenn die Schlüssel Spielobjekte bezeichnen, etwa {"door": door_rect, "crate": crate_rect}. Beide Dictionary-Methoden sind in der offiziellen Pygame-Rect-Dokumentation beschrieben.
Überlappt ein Spielerrechteck beispielsweise die Werte für "crate" und "door", liefert player.collidedict(rectangles, use_values=True) ein passendes Schlüssel-Rechteck-Paar zurück, während player.collidedictall(rectangles, use_values=True) beide Paare zurückgibt. Die API-Aufrufe stehen als Inline-Beispiele, weil beim Import von Pygame in der konfigurierten Laufzeit eine plattformspezifische Warnung ausgegeben wird. Die Ergebnisse beschreiben das dokumentierte API-Verhalten und wurden hier nicht zur Laufzeit überprüft. Die Methode für einen einzelnen Treffer eignet sich, wenn irgendein Treffer ausreicht; verwende die Variante für alle Treffer, wenn das Spiel jede Überlappung behandeln muss. Über einen zurückgegebenen Schlüssel kannst du das getroffene Rechteck seinem Objekt zuordnen; die Methode legt jedoch keine Reaktion auf die Kollision fest.
Prüfen, ob sich zwei Kreise überlappen
Pygame stellt für Rect keine Methode collidecircle() bereit. Berechne bei Kreisen mit den Mittelpunkten (x1, y1) und (x2, y2) sowie den Radien r1 und r2 den Abstand zwischen den Mittelpunkten und vergleiche ihn mit der Summe der Radien. Die Kreise berühren oder überlappen sich, wenn der Abstand kleiner oder gleich r1 + r2 ist. Für eine boolesche Prüfung kannst du die quadrierten Werte vergleichen und so das Ziehen einer Quadratwurzel vermeiden:
(x1 - x2) ** 2 + (y1 - y2) ** 2 <= (r1 + r2) ** 2
Halte Mittelpunkt und Radius mit der Position des jeweiligen Objekts synchron. Diese Berechnung setzt kreisförmige Trefferbereiche voraus und ist keine genaue Prüfung für ein nicht kreisförmiges Sprite.
Pixelgenaue Überlappung mit Masken prüfen
Wenn rechteckige Hitboxen für transparente oder unregelmäßige Spriteformen zu ungenau sind, erstelle mit pygame.mask.from_surface(surface) Masken aus den Oberflächen. Prüfe zuerst mit colliderect() grob, ob sich die Rechtecke überlappen; erst dann solltest du Masken erstellen oder abfragen. Rufe anschließend first_mask.overlap(second_mask, offset) auf. Der Offset gibt die Position der zweiten Maske relativ zur ersten an und lautet häufig (second_rect.x - first_rect.x, second_rect.y - first_rect.y). Mask.overlap() gibt bei mindestens einem überlappenden undurchsichtigen Pixel einen Punkt zurück, andernfalls None. Informationen zum Erstellen von Masken und zur Überlappungsprüfung enthält die offizielle Pygame-Masken-Dokumentation.
Masken verursachen mehr Rechenaufwand als Rechteckprüfungen. Verwende sie daher nur, wenn die zusätzliche Genauigkeit das Spiel verbessert. Maskiere unveränderte Oberflächen einmal und verwende die Masken wieder, statt sie in jedem Frame neu zu erstellen. Geprüft werden Maskenpixel, nicht visuelle Effekte wie Schatten oder Leuchten, sofern diese Pixel nicht in der Quelloberfläche enthalten sind.
Eine kleine eigenständige Geometrieillustration kann die Entscheidung zur Rechtecküberlappung zeigen, ohne ein Pygame-Fenster oder Bilddateien zu benötigen. Sie besteht aus einfacher Python-Logik und prüft nicht die Pygame-API.
Der Code und die angezeigten Bezeichnungen oder Ausgaben in diesem Abschnitt bleiben auf Englisch.
first = (100, 100, 50, 50)
second = (120, 120, 50, 50)
def overlaps(a, b):
ax, ay, aw, ah = a
bx, by, bw, bh = b
return ax < bx + bw and bx < ax + aw and ay < by + bh and by < ay + ah
print(overlaps(first, second))
True