Pixelgenaue Kollisionserkennung mit PIL

Stellt hier eure Projekte vor.
Internetseiten, Skripte, und alles andere bzgl. Python.
Antworten
Benutzeravatar
kaytec
User
Beiträge: 608
Registriert: Dienstag 13. Februar 2007, 21:57

Hallo,

habe mal verucht eine pixelgenaue Kollisionserkennung zu basteln. WIrd auf meinem Rechner (Aspire one), bei der Überschneidung der BBoxes langsamer, da ich eine Liste mit den äußeren Punkten ohne Transparenz erstelle und diese vergleiche.

http://www.python-forum.de/pastebin.php?mode=view&s=152

Gruß Frank
BlackJack

Ich würde ja eher auf pygame.sprite.collide_mask() bauen als mir da in Python was langsames selber zu basteln.

Edit: Ups habe gar nicht gesehen, dass es nicht um Pygame ging. Aber grundsätzlich wäre etwas mit Transparenz und Bildoperationen vielleicht auch mit PIL eine gute Idee.
Benutzeravatar
kaytec
User
Beiträge: 608
Registriert: Dienstag 13. Februar 2007, 21:57

@BlackJack : Ich verwende doch Pil ?

Gruß Frank

edit: gesteuert wird mit den Pfeiltasten.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Ich habe mir Deinen Code nicht genauer angeguckt, aber vielleicht kannst Du die Reihenfolge optimieren, in der Du Objekte auf Kollision prüfst? Also ggf. diejenigen, bei denen es wahrscheinlicher ist, zuerst, manche gar nicht usw.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Benutzeravatar
kaytec
User
Beiträge: 608
Registriert: Dienstag 13. Februar 2007, 21:57

@ Hyperion: Es werden zwar alle Objekte geprüft, doch nur bei einer Überschneidung der BBoxes fängt das Vergleichen über Listen an und da macht es Probleme.

Gruß Frank
BlackJack

@kaytec: Du verwendest PIL aber nicht für die Kollisionserkennung soweit ich das sehe. Ich meine Bildoperationen auf Transparenzmasken, also zum Beispiel eine Und-Verknüpfung von zwei Bitmasken die auf der Transparenz basieren und dann schauen ob Pixel gesetzt sind.
Benutzeravatar
kaytec
User
Beiträge: 608
Registriert: Dienstag 13. Februar 2007, 21:57

@BlackJack: Für die Kollisionerkennung nicht - ich lese mit Pil nur die Punkte am Umfang des Objektes aus und diese vergleiche ich dann mit den Punkten des anderen Objektes. Das mit Bitmasken ... und so weiter verstehe ich jetzt nicht ?

Gruß Frank
BlackJack

@kaytec: Wenn man aus den Bildern Schwarz/Weiss-Bilder erstellt bei denen die nicht-transparenten Pixel gesetzt sind, kann man beide Bilder -- entsprechend der Positionen verschoben -- Und-Verknüfen. Wenn im Ergebnis Pixel gesetzt sind, dann kollidieren die nicht-transparenten Teile der Bilder, ansonsten halt nicht.

Rufst Du `build_shape()` eigentlich bei jeder Überprüfung auf!? Da sollte man vielleicht über eine Klasse nachdenken die das Bild und das dazugehörige "shape" kapselt und die "shape"-Daten nur *einmal* berechnet.
Benutzeravatar
kaytec
User
Beiträge: 608
Registriert: Dienstag 13. Februar 2007, 21:57

@BlackJack: Ich habe es zuerst mit einem kompletten Bild ohne Transparenz versucht und dann hatte ich bei dem Raumschiff an die 1200 Bildpunkte, deswegen habe ich es auf die Umrisse begrenzt. Ich erzeuge bei jedem Vergleich eine neue Liste, da sich die Koordinaten der Bildpunkte ja ständig verändern.

Gruß Frank
Benutzeravatar
kaytec
User
Beiträge: 608
Registriert: Dienstag 13. Februar 2007, 21:57

Hier mal ein kleines Beispiel mit dem Auslesen der Daten auf Transparenz

Code: Alles auswählen

import base64
import StringIO
from PIL import Image
ENEMY_SHIP = """R0lGODlhIQANAKECAAAAAPhIH////////yH5BAEKAAAALAAAAAAhAA0AAAIyhI
                8Yt+kPQwMS2ihzvpzqv3UOSFaiUaYmp7bXh8ZyA481zcw1qvFt79mATo8f0fZL
                /goAOw=="""

im = Image.open(StringIO.StringIO(base64.decodestring(ENEMY_SHIP))).convert("RGBA")
im.load()
row = list()

shape = list()
for rgba in list(im.getdata()):
    if rgba[3] == 0:
        transparency = 0
    else:
        transparency = 1
    row.append(transparency)
    if len(row) == im.size[0]:
        shape.append(row)
        row = list()
for row in shape:
    print row
Gruß Frank
Benutzeravatar
kaytec
User
Beiträge: 608
Registriert: Dienstag 13. Februar 2007, 21:57

Hallo !

Ich habe das Problem gelöst. Ich erstelle die Shapes vorher und zähle später nur die aktuelle Position hinzu, indem ich Bezug auf linke obere Ecke des Spielfeldes nehme,

http://www.python-forum.de/pastebin.php?mode=view&s=153

Gruß Frank
Benutzeravatar
kaytec
User
Beiträge: 608
Registriert: Dienstag 13. Februar 2007, 21:57

Hallo !

habe noch einige Verbesserungen vorgenommen.

http://www.python-forum.de/pastebin.php?mode=view&s=156

Gruß Frank
Benutzeravatar
kaytec
User
Beiträge: 608
Registriert: Dienstag 13. Februar 2007, 21:57

Hallo,

habe die Kollisionserkennung aufgeteilt, damit es die Möglichkeit zur pixelgenauen Erkennung und zur Erkennung mit bbox gibt.

Feuern mit Space und Lenkung mit Pfeiltasten.

http://www.python-forum.de/pastebin.php?mode=view&s=157

Gruß Frank
Antworten