ATTENTION READERS! Lucky's VB Gaming Site is no longer active. For updated game programming information and tutorials, please visit The Game Programming Wiki!
Pixelgenaue Kollisionsabfrage
Eins kann ich euch jetzt schon sagen, dieses Tutorial wird
kurz und schmerzlos... und sehr, sehr fortgeschritten! Ich werde
mir nicht die Mühe machen, euch zu erklären, wie die
Initialisierung und Terminierung von DirectDraw, das laden von
Surfaces, die Rechteckskollisionsabfrage, usw. funktioniert.
Falls ihr diese Dinge noch nicht beherrscht, dann glaube ich,
dass ihr noch nicht für Pixel-Manipulations-Techniken bereit
seid.
Also, los geht's!
Wir werden die DirectDrawSurface7.GetLockedArray-Methode
verwenden, um die Farbwerte jedes Pixel unserer Surface zu
extrahieren. Natürlich müssen wir zuerst DirectDrawSurface7.Lock
aufrufen, und diese Methode akzeptiert eine menge Argumente:
- r as RECT - Das Rechteck, innerhalb einer Surface,
welches ich sperren wollt... theoretisch! Denn eigentlich, egal
wie groß euer Rechteck ist, werdet ihr eh die ganze Surface
sperren! Aber das macht nichts, wie ihr sehen werdet.
- desc As DDSURFACEDESC2 - Nach dem Lock-Aufruf
(sichern/sperren) wird diese Variable mit der Beschreibung der
gesicherten Surface gefüllt.
- flags As CONST_DDLOCKFLAGS - Wir werden folgende Flags
(Argumente) verwenden: DDLOCK_READONLY und DDLOCK_WAIT,
da wir nur Daten lesen wollen und keinen Fehler auslösen
möchten (durch das Zugreifen auf eine unvorbereitete Surface).
- hnd As Long - Das SDK sagt, dass dieser Parameter nicht
benutzt wird, also setzen wir ihn auf null.
Die GetLockedArray-Methode selber nimmt nur
ein Argument an, ein Byte-Datenfeld (Beachtet, dass dieses Array
DYNAMISCH SEIN MUSS!), dass mit den Surface-Daten gefüllt wird.
Ein Beispiel:
Dim bytMoving() As Byte
msurfMovingObj.GetLockedArray bytMoving
Wenn wir diesen Code ausführen, nachdem wie die Surface
gesperrt (engl.: Lock) haben, werden wir ein Array erhalten, dass
auf einen Speicherbereich der Surface ZEIGT. Beachtet, dass dies
nur ein Zeiger ist... das Datenfeld selber wird diese Daten nicht
mehr enthalten, nachdem wir die Surface wieder freigegeben
(Unlock) haben! Das mag zwar ziemlich umständlich erscheinen,
aber es ist sehr nützlich. Es erlaubt uns nur auf die Pixel
zuzugreifen, deren Werte wir benötigen... die restlichen können
wir einfach ignorieren. Da das untersuchen der Pixel-Daten eine
sehr zeitspielige Angelegenheit ist, können wir gebrauch dieses
Vorteils der GetLockedArray-Methode machen, um
die Zeit, die für die Kollisionsabfrage benötigt wird, zu
minimieren.
Wie? Wir sperren beide Surfaces und gehen Pixel für Pixel
durch die sich überschneidenden Flächen der beiden Surfaces und
untersuchen die Pixel-Werte. Durch das Auslassen der
nicht-überlappenden Flächen sparen wir einiges an Zeit (das
überlappende Rechteck (RECT) erhalten wir, durch den Einsatz der
IntersectRect API), und
durch den gleichzeitigen Vergleich der Pixel der Surfaces,
können wir eine Kollision melden, sobald auch nur eine
Überlappung entdeckt wurde! Das ist der für euch am
effizientesten funktionierende Algorithmus, um Kollisionen
zwischen unregelmäßigen Objekten festzustellen (reglemäßige
Objekte könnten Eigenschaften aufweisen, die euch eine weitere
optimierung ermöglichen).
Ich werde hier nicht weiter auf die Einbindung eingehen, da es
sich einfach nur um das Auffinden eines überlappenden Rechtecks
(RECT) und einen Pixel-Vergleich handelt. Seht euch den Quellcode an und es wird euch alles klar!