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.
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.
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:
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 |
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.
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.
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 BitmapData
hitTest-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"
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:
hitTestObject ()
um zu sehen, ob die Begrenzungsrahmen zweier Objekte kollidiert sind.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.
Danke fürs Lesen. Im nächsten Quick Tip verwenden wir Matrizen zum Transformieren BitmapData
.