Kollisionserkennung auf Pixelebene

Bisher waren unsere Kollisionserkennungsmethoden mathematisch fundiert. Obwohl dies hilfreich ist, gibt es Fälle, in denen sich der mathematische Ansatz nicht lohnt, beispielsweise bei einer unregelmäßigen, organischen Form - die erforderlichen Berechnungen sind zu komplex und zu teuer, um sie zu rechtfertigen. Stattdessen können wir jedes einzelne Pixel der Formen überprüfen. Dies ist auch ein teurer Ansatz, kann aber zumindest optimiert werden.


Kollisionserkennung

Dies ist das letzte Stück, das wir zu schaffen versuchen werden. Ziehen Sie den Haken über den Kokosnussbaum und notieren Sie, was der Text unten sagt.


Schritt 1: Einer nach dem anderen

Angenommen, wir haben zwei Bitmaps, und wir möchten prüfen, ob sie Pixel für Pixel kollidieren: Was bedeutet das? Nehmen wir an, beide Bitmaps sind 3x3px und alle Pixel sind gefüllt.

Wir werden buchstäblich folgendes tun:

  1. Prüfen Sie, ob a1 und b1 den gleichen Ort haben.
  2. Wiederholen Sie Schritt (1), aber jetzt für a1 und b2.
  3. Wiederholen Sie dasselbe zwischen a1 und b3, b4… b9.
  4. Wiederholen Sie die Schritte (1) bis (3) für a2, a3… a9.

Es gibt einige Bemerkungen, auf die ich hinweisen möchte.

Überwachung Beschreibung
Pixel oben links Die oberen linken Pixel für beide Bitmaps werden als Startpixel für Überprüfungen verwendet. Beispiel: a1 ist das Startpixel, das mit allen Pixeln in b abgeglichen wird, das mit b1 beginnt. Beide oberen linken Pixel.
Zeilenverlauf abtasten Wie bereits erwähnt, erfolgt die Überprüfung in der Reihenfolge von a1, a2, a3… a9. Beachten Sie die Anordnung dieser Pixel.
Gemeinsamer Koordinatenraum Angenommen, beide Grafiken werden der Anzeigeliste der Bühne hinzugefügt. Die Position jedes Pixels in beiden Bitmaps, im Koordinatenraum der Bühne, wird verglichen, um zu sehen, ob es zu Überschneidungen kommt.
Teure Berechnung Für zwei 3x3-Bitmaps sind maximal 9x9-Wiederholungen erforderlich. Wenn meine Bitmap-Größe 100x100 beträgt, können Sie sehen, wie schnell die Gesamtberechnung wächst. Wenn jedoch eine Prüfung ein positives Ergebnis liefert, können die restlichen Prüfungen abgebrochen werden, da, wenn ein Pixel in beiden Bitmaps überlappt, wir sagen können, dass eine Kollision zwischen den Bitmaps auftritt

Schritt 2: Zusätzliche Überlegungen

Nun kann Schritt 1 wörtlich genommen werden, wenn alle Pixel gefüllt sind. Mit Bitmap-Grafiken definieren wir einen rechteckigen Bereich. Es werden jedoch nicht alle Pixel gefüllt, um die Grafik zu bilden.

Das folgende Beispiel zeigt die rechte Bitmap, die nur b2, b4, b5, b6 und b8 belegt. In diesem Fall sollten wir jedes Pixel in der linken Bitmap (a1, a2, a3… a9) nur mit den Pixeln b2, b4, b5, b6, b8 in der rechten Bitmap überprüfen.

Jetzt enthält ActionScript einen weiteren Parameter, Alpha, was die Transparenz des Pixels definiert, wobei 0 vollständig transparent und 1 vollständig undurchsichtig ist. Für b2, b4, b5, b6, b8 können wir einen Schwellenwert für definieren Alpha, sagen Sie 0.5.

Nehmen wir also an, dass b2 und b8 beide Pixel mit sind Alpha 0,1; Da sie unter dem Schwellenwert von 0,5 liegen, werden wir sie nicht als gefüllte Pixel betrachten und daher nicht prüfen. Am Ende wird also jedes Pixel in der linken Bitmap (a1, a2, a3… a9) nur in der rechten Bitmap gegen b4, b5, b6 geprüft.


Schritt 3: ActionScript-Implementierung

In ActionScript können wir Vektorgrafiken einblenden BitmapData Instanzen. Sie können sich vorstellen, dass ActionScript ein Röntgenbild einer Vektorgrafik erstellt und in ein Format überträgt BitmapData, das wirkt wie der fotografische Film.

(Tipp: Wenn Sie in Flash IDE zeichnen und dann wie ich nach FlashDevelop exportieren, vergewissern Sie sich, dass die Abmessungen der BitmapData sind groß genug, um die Zeichnung zu enthalten.)

Hier, CTree und Haken sind zwei MovieClip-Symbole, die in Flash gezeichnet werden. Wir "röntgen" sie, um für jede eine BitmapData-Instanz zu erhalten:

 Private Var Coconut: CTree, hk: Haken; private var bdat1: BitmapData, bdat2: BitmapData; private var t1: TextField; öffentliche Funktion Matrix_Bitmap () coconut = new CTree (); addChild (Kokosnuss); coconut.x = stage.stageWidth * 0,3; coconut.y = stage.stageHeight * 0,2; bdat1 = new BitmapData (150, 150, true, 0x00000000); bdat1.draw (Kokosnuss); hk = neuer Hook (); addChild (hk); bdat2 = new BitmapData (100, 50, true, 0x00000000); bdat2.draw (hk); hk.addEventListener (MouseEvent.MOUSE_DOWN, start); hk.addEventListener (MouseEvent.MOUSE_UP, end); t1 = neues Textfeld (); addChild (t1); t1.x = stage.stageWidth * 0,2; t1.y = stage.stageHeight * 0,8; t1.breite = 300; t1. Höhe = 100; stage.addEventListener (Event.ENTER_FRAME, überprüfen); 

Danach starten wir die Prüfung mit der hitTest () Methode der BitmapData Klasse.

Bei jedem durchlaufenden Frame aktualisieren wir die Position des oberen linken Pixels für jede Bitmap, bevor Instanzen von gesetzt werden BitmapData durch diese rigorosen hitTest () prüft. Beachten Sie auch, dass der Bereich für Alpha Die Eingabe hier ist 0 ~ 255 - d. h. es gibt keine Schwelle. Mehr zur Transparenz im nächsten Schritt.

 private Funktionsprüfung (e: Event): void var point1: Point = new Point (coconut.x, coconut.y); // oberes linkes Pixel des Baumes var point2: Punkt = neuer Punkt (hk.x, hk.y); // oberes linkes Pixel des Hooks if (bdat1.hitTest (Punkt1, 255, Bdat2, Punkt2, 255)) // Prüfen, ob sich gefüllte Pixel überlappen t1.text = "Mindestens ein Pixel hat kollidiert" else t1 .text = "Keine Kollision"

Hier ist ein Beispiel für die Ausgabe von ActionScript. Klicken Sie auf den Haken und bringen Sie ihn in die Nähe des Kokosnussbaums. Überprüfen Sie die Antwort im Textfeld. Spielen Sie damit herum, indem Sie das Ende des Hakens nahe an den Rand der Blätter des Kokosnussbaums bringen, um zu sehen, ob diese Kollision Pixelgenau ist.


Schritt 4: Transparenzstufe

Wenn Sie ein Bild haben, das beispielsweise allmählich verschwindet (transparent wird), können Sie ActionScript mitteilen, auf welcher Transparenzebene Sie ein Pixel als geeignet betrachten, um Kollisionsprüfungen durchzuführen.

Nehmen Sie das Beispiel unten: Es gibt mehrere Transparenzstufen für das Sprite, und wie Sie sehen, wird es allmählich nach rechts abgesenkt. Wenn wir den Transparenzgrad auf 0,5 einstellen, wird jedes Pixel mit einem Alpha von 0,5 ~ 1 als undurchsichtig und für die Kollisionserkennung geeignet betrachtet. Die unter 0,5 werden als transparent betrachtet. Selbst wenn diese Pixel mit einem anderen Objekt kollidieren, wird keine echte Kollision registriert.

Ein weiteres Detail, das ich gerade erwähnt habe, ist ActionScript BitmapDatahitTest-Funktion Alpha Der Parameterwert liegt tatsächlich im Bereich von 0 bis 255. Also muss ich einfach meinen Schwellenwert mit 255 multiplizieren, um den Bereich zu konvertieren.

 private Funktionsprüfung (e: Event): void var point1: Point = new Point (bar1.x, bar1.y); var point2: Punkt = neuer Punkt (bar2.x, bar2.y); var Schwelle: Anzahl = 255 * 0,5 if (bdat1.hitTest (Punkt 1, Schwelle, Bdat2, Punkt 2, Schwelle)) t1.text = "Mindestens ein Pixel hat kollidiert" else t1.text = "Keine Kollision" 

Schritt 5: Optimierung

Ich habe erwähnt, dass die Kollisionserkennung auf Pixelebene rechenintensiv ist. Das heißt, wir sollten uns nur für das entscheiden, wenn es unbedingt notwendig ist. Wenn zwei Objekte sehr weit voneinander entfernt sind, gibt es keinen Grund, diesen Ansatz zu verwenden und eine normale Kollisionserkennung (hitTestObject ()) Wird besorgt.

Hier ist die Idee:

  1. Benutzen hitTestObject () um zu sehen, ob die Begrenzungsrahmen zweier Objekte kollidiert sind.
  2. Wenn die Antwort ja ist, sind diese beiden Objekte ziemlich nahe. Fahren Sie mit der Überprüfung auf Pixelebene fort.
  3. Wenn die Antwort nein ist, liegen diese beiden Objekte weit auseinander. Beenden Sie die Kollisionsprüfung ohne Prüfung auf Pixelebene.
 private Funktionsprüfung (e: Event): void var closeEnough: Boolean = coconut.hitTestObject (hk) if (closeEnough) var Punkt1: Punkt = neuer Punkt (coconut.x, coconut.y); var point2: Punkt = neuer Punkt (hk.x, hk.y); if (bdat1.hitTest (point1, 255, bdat2, point2, 255)) t1.text = "Mindestens ein Pixel ist kollidiert" else t1.text = "Keine Kollision"

Eine vollständige Referenz zu ActionScript finden Sie hier Matrix_Bitmap3.as aus dem Quelldownload herunterladen.


Fazit

Danke fürs Lesen. Im nächsten Quick Tip verwenden wir Matrizen zum Transformieren BitmapData.