GrafikProgrammierung in Pascal - Teil 3 Wiedermal gibt's zuerst den "richtigen" Aufruf des FPC-Compilers: ppc386 -Scg -Xs -OG5 x.pas Und jetzt... zu etwas v”llig Anderem... Heute widmen wir uns den Sprites, den wohl wichtigsten Grafikroutinen jedes Spiels (mal abgesehen von den neueren 3D-Games). Sprites kann man wohl am besten als rechteckige Bilder beliebiger Gr”áe definieren, die ebenso beliebig auf dem Bildschirm verteilt werden k”nnen. Eine Raffinesse dieser Sprites besteht auáerdem darin, "durchsichtig" sein zu k”nnen, soll heissen, das z.B. alle Pixel eines Sprites mit der Farbe 0 einfach nicht dargestellt werden und somit der Hintergrund erhalten bleibt. Jetzt zur Umsetzung: Erstmal mssen wir jederzeit wissen, wie lang und hoch unser Sprite ist und an welchem Speicherbereich sich unser "Bild" befindet. TYPE Sprite = record dtx,dty : longint; { Breite, H”he } adr : pointer; { Speicher-Adresse an der das "Bild" beginnt } end; Nun die eigentliche Zeichenroutine: Der Ansatz l„uft so, das zuerst mal festgestellt wird, ob man unser Sprite berhaupts sehen kann, also ob es mit den bergebenen Koordinaten innerhalb des sichtbaren Bildbereiches liegt, oder nicht. Weiterhin sollte berprft werden, ob das Sprite direkt an einer "Grenze" des Bildschirms liegt und "abgeschnitten" werden muá. Bsp. Command & Conquer: Ein Panzer bewegt sich von der Basis (Mitte des Bildschirms) zum linken Bildrand. Am Anfang sieht man ihn komplett, dann nur noch stckweise, bis er vom Bild "verschwunden" ist. Dieses Stckweise-Darstellen (Clipping) ist immens wichtig !! Der Bildspeicher liegt schliesslich "an einem Stck" vor (64000 Bytes). Das erste Byte liegt dabei links oben am Bildschirm, das 64000te rechts unten. Wenn nun besagter Panzer mit ein paar Pixeln den linken Rand erreicht hat, wrden ebendiese Pixel beim n„chsten Zug am rechten Rand auftauchen, bis der ganze Panzer auf der rechten Seite reinf„hrt... Schlimmer w„re das Ganze am oberen/unteren Bildrand. Bei einer šberquerung wrden wir munter in Speicher reinschreiben, der uns gar nix angeht -> bestenfalls Fehlermeldung, wenn nich gar Rechner-Absturz w„ren die Folge. Die Umsetzung: Zun„chst einmal der Rumpf, in dem berprft wird, ob das Sprite sichtbar ist und wenn ja, wieviel davon: PROCEDURE PutSprite(dest : pointer; x,y : longint; spr : sprite); Var clipl,clipr,clipo, destskip,sprskip : longint; BEGIN x:=x-spr.dtx shr 1; { Wird ben”tigt, um das Sprite "mittig" zu setzen } y:=y-spr.dty shr 1; { -> Bsp. x=160/y=100 -> Mittelpunkt des Sprites ist bei 160/100 } if (x+spr.dtx<0) or (x>=320) or (y+spr.dty<0) or (y>=200) then exit; { links auáerhalb, rechts auáerhalb, oben auáerhalb, unten auáerhalb ?? Wenn ja -> raus } clipr:=0; { Alle Variablen 0 = kein Abschneiden (Clipping) } clipl:=0; clipo:=0; if (y<0) then begin clipo:=-y*spr.dtx; spr.dty+=y; y:=0; end; if (y+spr.dty>=200) then spr.dty:=200-y; if (x<0) then begin clipl:=-x; spr.dtx+=x; x:=0; end; if (x+spr.dtx>=320) then begin clipr:=(x+spr.dtx)-320; spr.dtx:=320-x; end; { Wenn am Rand, dann Spritel„nge/h”he, x/y und Clipping-Variablen ver„ndern } if (spr.dtx<=0) or (spr.dty<=0) then exit; { Zur Sicherheit berprfen, ob durch Clipping gar nichts mehr darzustellen ist } dest+=x+y*320; { Im Videospeicher an Anfangs-Zeichen-Position des Sprites rcken } spr.adr+=clipo+clipl; { Im "Spritespeicher" an erstes Pixel rcken, das dargestellt wird } destskip:=320-spr.dtx; { Um diesen Wert mssen wir pro gezeichneter (waagrechter) Linie im Videospeicher weiter } sprskip:=clipl+clipr; { Das gleiche fr den Spritespeicher (Bei Clipping !!) } ... ... Noch ein paar Erkl„rungen dazu: Als erstes werden x und y Wert so ver„ndert, das sie die Position des ersten Pixels des Sprites angeben (linke, obere Ecke). Dann wird berprft, ob das Sprite sichtbar ist. Anschliessend wird fr jeden Bildrand geprft, ob das Sprite sich an einer Grenze befindet. Ist dies der Fall wird berechnet, wieviel Pixel des Sprites abgeschnitten werden mssen (Beim oberen Rand muá dabei mit spr.dtx multipliziert werden, um an den "neuen" ersten Pixel zu gelangen, der dargestellt werden muá). Auáerdem wird die Startadresse im Videospeicher mittels x/y ver„ndert. Zuguterletzt werden dann die Speicheradressen mit diesen Variablen berechnet. Alles was dann folgt ist sehr simpel: In den Video-Speicher (dest) schreiben wir spr.dtx-mal die Pixel, die wir aus unserem Sprite-Bild (spr.adr) ziehen. Anschliessend wird im Video-Speicher um destskip Pixel weitergerckt und im Sprite-Bild um sprskip Pixel. Die erste waagrechte Linie w„re damit gezeichnet. Das wiederholt man dann insgesamt spr.dty-mal. Um nun Transparenz darzustellen, wird einfach bei jedem Pixelsetzen berprft, ob der Pixel die Farbe 0 hat (durchsichtig) oder eine Andere (undurchsichtig). Warum gerade Farbe 0 ??? Ganz einfach: Da die Zeichenroutine in Assembler gehalten ist, bediene ich mich eines Tricks (fr ASM-Fortgeschrittene: Aus einem "cmp al,0" wird ein "or al,al"), um die Geschwindigkeit damit zu erh”hen. Also ran an den Quelltext und ausprobieren (Die Routinen sind aufgeteilt in TransSprite (Farbe 0 = durchsichtig) und SolidSprite (komplett undurchsichtig)). N„chstes Mal gibt's nen simplen PCX-Reader, mit dem wir dann prima Sprite-Bilder einlesen k”nnen... BYE BYE... Carsten aka Toxic Avenger/Ainc.