2.4 |
Die
Sprite-Engine |
[ Top ]
|
Um
einen Sprite zu zeichnen, müssen wir wissen, wo die Maske
ist, wo die Bitmap ist und wohin der Sprite gezeichnet
werden soll. (Hier noch einmal das Schema aus dem vorherigen
Teil): |
|
Ein
Sprite besteht also aus der Maske, der Bitmap und der
Position, an die er gezeichnet werden soll. Daraus wird auch
der Datentyp Sprite bestehen. Doch zuerst noch ein anderer,
wichtiger Datentyp: |
|
|
Type
pos
X As Integer
'X-Position (linker Rand)
Y As Integer
'Y-Position (oberer Rand)
W As Integer 'Breite des Rechtecks
H As Integer 'Höhe des Rechtecks
HDC As Integer 'DeviceContext des Bildfelds
End Type
|
|
|
Wie
Sie den Kommentaren hinter den Elementen von “pos”
entnehmen können beinhaltet “pos” die Koordinaten eines
Rechtecks und ein DC. Damit können Sie einen Bildausschnitt
auf einem beliebigem Bildfeld definieren: |
|
Der
Datentyp pos kann nun sehr vielseitig eingesetzt
werden: Er kann für die Maske, für die Bitmap und auch für
die spätere Position des Sprites eingesetzt werden: |
|
|
Type
Sprite
Bit As pos 'Bilddaten
Maske As pos
'Maske
Nach As pos
'Position, an der das Sprite
angezeigt werden soll
End Type
|
|
|
Der
Datentyp Sprite basiert nun auf dem Datentyp Pos. Das
scheint vielleicht auf den ersten Blick umständlich, jedoch
werden Sie sehen, dass es eine Vielzahl von neuen Möglichkeiten
gibt. Ein Sprite besteht nun aus den Variablen Bit, Maske
und Nach des Typs Pos. |
Nachdem wir
nun den Aufbau eines Sprites festgelegt haben, kommen natürlich
die Prozeduren zum Erstellen und Anzeigen von Sprites. |
|
|
Sub
POS_SET(P As pos,
X, Y, W, H, PicBox As
PictureBox)
P.X = X
P.Y = Y
P.W = W
P.H = H
P.HDC = PicBox.HDC
End Sub
|
|
|
Warum
denn schon wieder POS? Ich dachte, jetzt kämen die
Sprite-Prozeduren! Schon richtig, aber da Sprites ja auf
Variablen des Typs “Pos” basieren benötigen wir auch
Funktionen, mit denen wir diese Variable leicht ändern können.
Die Prozedur POS_SET macht nichts anderes, als der
Variable P die Werte X, Y, W, H und das DeviceContext von PicBox
zuzuweisen. PicBox ist, wie Sie oben sehen eine
Variable des Typs PictureBox. Mit anderen Worten:
Hier wird ein Bildfeld übergeben! Hier ein Beispiel, wie
man mit POS_SET einen Sprite setzen kann: |
|
|
Dim
Spr As Sprite
POS_SET Spr.Bit, 0, 0, 100, 100, RESSOURCEN.RES(1)
POS_SET Spr.Maske, 0, 0, 100, 100, RESSOURCEN.RES(2)
POS_SET Spr.Nach, 0, 0, 100, 100, DISPLAY
|
|
|
So
kann könnte man die Position der Bitmap, der Maske und die
Ausgangsposition festlegen. Und warum ist das nun einfacher?
Tja, das sieht natürlich recht umständlich aus, aber keine
Angst, das Programm nimmt Ihnen diese Arbeit ab! In den
seltensten Fällen werden Sie selbst die Prozedur POS_SET
benutzen. |
Eine
vereinfachte Funktion von POS_SET gibt es übrigens
auch:
|
|
|
Sub
POS_SET_MAX(P As pos, PicBox As PictureBox)
P.X = 0
P.Y = 0
P.W = PicBox.ScaleWidth
P.H = PicBox.ScaleHeight
P.HDC = PicBox.HDC
End Sub
|
|
|
Diese
Funktion setzt die Variable P des Typs pos so, dass
das Rechteck das ganze Bildfeld PicBox ausfüllt. Das
Rechteck hat also die Startposition 0, 0 und die gleiche
Breite und Höhe wie das übergebene Bild. Auch diese
Funktion wird im Normalfall nur von der Engine selbst
benutzt. |
Nun aber zu
den Sprite-Funktionen, mit denen Sie bzw. die Engine später
arbeiten werden:
|
|
|
Sub
SPRITE_SET(S As Sprite,
Bit As Pos,
Maske As Pos)
S.Bit = Bit
S.Maske = Maske
S.Nach.X = 0
S.Nach.Y = 0
S.Nach.W = Bit.W
S.Nach.H = Bit.H
End Sub
|
|
|
Die
Prozedur SPRITE_SET erwartet als Parameter einmal den
zu setzenden Sprite und danach zwei Variablen des Typs pos,
die die Position der Bitmap und der Maske angeben. Hier
sehen Sie, dass die Variable "Nach", die ja auch
zum Datentyp Sprite gehört nicht voll benutzt wird.
Deren Werte X, Y und HDC brauchen nicht gesetzt zu werden,
da wir die Position des Sprites beim Zeichnen bestimmen. |
|
|
Sub
SPRITE_SET_MAX(S As Sprite,
Bit As PictureBox,
_
Maske As PictureBox)
Dim B As Pos, M As Pos,
N As Pos
POS_SET_MAX B, Bit
POS_SET_MAX M, Maske
SPRITE_SET S, B, M
End Sub
|
|
|
Die
Prozedur SPRITE_SET_MAX setzt ebenfalls einen Sprite,
diesmal wird jedoch nur übergeben, welches Bildfeld die
Bitmap und welches Bildfeld die Maske enthält. Der Sprite
wird dann so eingestellt, dass jeweils die ganze Bildfelder
benutzt werden. Lassen Sie sich jetzt nicht verwirren, es
folgt noch eine Übersicht der SPRITE_SET-Prozeduren
und ihrer Wirkung! |
|
|
Sub
SPRITE_SET_MAX(S As Sprite,
X, Y, W, H, Bit As PictureBox,
_
Maske As PictureBox)
S.Bit.X = X
S.Bit.Y = Y
S.Bit.W = W
S.Bit.H = H
S.Bit.HDC = Bit.hDC
S.Maske = S.Bit
S.Maske.HDC = Maske.hDC
S.Nach.X = 0
S.Nach.Y = 0
S.Nach.W = W
S.Nach.H = H
End Sub
|
|
|
Diese SPRITE_SET-Prozedur
setzt einen Sprite an Hand der übergebenen Position (X, Y,
W, H). Zusätzlich wird noch das Bildfeld mit der Bitmap und
das Bildfeld mit der Maske übergeben. Der Zweck dieser
Prozedur ist es, möglichst einfach einen Sprite zu
definieren, wenn die Maske an der gleichen Position liegt,
wie die Bitmap nur halt in einem anderen Bildfeld. |
Jetzt kommt
die SPRITE_SET-Prozedur, die den Aufwand mit Pos, SPRITE_SET_SYNC
usw. erforderlich macht: |
|
|
Sub
SPRITE_SET_MESH(Mesh() As Sprite, Start, X, Y, W, H, _
Pb1 As PictureBox, Pb2 As PictureBox)
YPos = 1
I = Start
For
Iy = 1 To Y
XPos = 1
For
Ix = 1 To X
SPRITE_SET_SYNC Mesh(I), XPos, YPos, W, H, Pb1, Pb2
I = I + 1
XPos = XPos + W + 1
Next Ix
YPos = YPos + H + 1
Next Iy
Start= I
End Function
|
|
|
Auf den
ersten Blick sieht diese Prozedur wahrscheinlich sehr wüst
aus, jedoch ist sie eigentlich ziemlich simpel. Diese
Prozedur geht davon aus, dass Sie ein Bild in mehrere gleich
große Rechtecke unterteilt haben und das in jedem Rechteck
ein Sprite ist. Als Parameter geben Sie bei dieser Prozedur
ein Datenfeld des Typs Sprite an, in die die definierten
Sprites aufgenommen werden. Anschließend folgt der
Startindex, ab dem gezählt wird. Danach folgen die Anzahl
der Kästchen in X-Richtung und die Anzahl der Kästchen in
Y-Richtung. Zum Schluss wird die Breite und die Höhe eines
Kästchens angegeben, sowie das Bildfeld mit der Bitmap und
der Maske. |
Im folgenden
finden Sie nun endlich eine anschauliche Darstellung der
einzelnen SPRITE_SET-Routinen: |
SPRITE_SET:
Diese Prozedur setzt
den Sprite aus zwei beliebigen Rechtecken zusammen. Das eine
Rechteck gibt die Bitmap, das andere die Maske an. Man kann
also frei wählen, woher man beides nimmt. Es ist damit auch
möglich, Bitmap und Maske in einem Bild unterzubringen.
|
|
SPRITE_SET_MAX:
Diese Routine setzt den Sprite aus zwei ganzen
Bildfeldern zusammen. Dieses Verfahren haben wir auch im
letzten Kursteil benutzt.
|
|
SPRITE_SET_SYNC:
Diese
Prozedur setzt den Sprite aus zwei Rechtecken zusammen, die
die gleiche Position haben, jedoch auf zwei
unterschiedlichen Bildern sind.
|
|
SPRITE_SET_MESH:
Diese Routine dient dazu, ein Bild in Sprites
umzuwandeln, dass in mehrere Kästchen unterteilt ist.
Dieses Verfahren werden wir im folgenden Kursteil ausführlich
besprechen. Sie werden dann auch sehen, warum diese Möglichkeit
im Endeffekt wesentlich schneller ist, als die anderen.
|
|
Und nun
die letzte Prozedur für heute:
|
|
|
Sub
SPRITE_DRAW(S As Sprite,
X, Y, PicBox As PictureBox)
S.Nach.hDC = PicBox.hDC
r% = StretchBlt(S.Nach.hDC, X, Y, S.Nach.W,
S.Nach.H,
S.Maske.hDC,
S.Maske.X, S.Maske.Y, S.Maske.W, _
S.Maske.H, BIT_AND)
r% = StretchBlt(S.Nach.hDC, X, Y, S.Nach.W,
S.Nach.H, _
S.Bit.hDC, S.Bit.X, S.Bit.Y,
S.Bit.W, S.Bit.H, BIT_INVERT)
End Sub
|
|
|
Diese
Prozedur bekommt als Parameter den Sprite S, die Position
und das Ausgabe-Bildfeld übergeben. Der Sprite wird nun
nach dem aus dem vorherigen Teil bekannten Verfahren auf das
Bildfeld an die Position X/Y gezeichnet. |
Wenn Sie in
diesem Teil nicht alle Prozeduren und Funktionen verstanden
haben, so ist das nicht weiter tragisch. Wie man die
Funktionen verwendet wird im nächsten Teil an Hand des
Pacman-Spiels gezeigt. Wenn Sie Lust haben können Sie bis
zum nächsten Mal ja selbst etwas mit diesen Routinen
arbeiten. |
|
|