Im 4. Teil werden wir unserem Helden Leben einhauchen und ihm beibringen, wie man schiesst.
Im angeh?ngten Beispielcode befinden sich neu die Grafikdaten f?r unser Spielersprite und die Sch?sse isdo/gfx/player.png.
In isdo.gbas definieren wir zuerst wieder einige neue Types, Konstanten und Variablen:
TYPE TPlayer
PosX = 64
PosY = 64
Timer% = 0
Dir% = 0
Speed = 1.0
ENDTYPE
PosX und PosY ist die Position, wo unser Spieler-Sprite angezeigt wird. Timer ist ein Z?hler der bei jedem Bildaufbau um 1 erh?ht wird. Dir ist die Bewegungsrichtung und Speed bestimmt die Bewegungsgeschwindigkeit.
TYPE TShot
State%[8]
PosX[8]
PosY[8]
Dir%[8]
Count% = 8
ENDTYPE
Hier definieren wir einen Typ f?r 8 Sch?sse. D.h. wir werden maximal 8 Sch?sse gleichzeitig anzeigen k?nnen.
State beschreibt den aktuellen Schussstatus, PosX und PosY die Position und Dir die Schussrichtung. Count ist die Anzahl der maximalen Sch?sse.
// sprites
GLOBAL SPR_PLAYER% = 3
GLOBAL SPR_SHOT% = 18
Damit wir uns beim Spritezeichnen nicht jedes Mal die entsprechenden Nummern merken m?ssen, bezeichnen wir diese mit einer ?bersichtlicheren Konstante.
// directions
GLOBAL DIR_UP% = 16
GLOBAL DIR_RIGHTUP% = 18
GLOBAL DIR_RIGTH% = 2
GLOBAL DIR_RIGHTDOWN% = 6
GLOBAL DIR_DOWN% = 4
GLOBAL DIR_LEFTDOWN% = 12
GLOBAL DIR_LEFT% = 8
GLOBAL DIR_LEFTUP% = 24
GLOBAL DIR_NONE% = 0
Das sind Richtungsangaben welche wir f?r das Spielersprite und die Sch?sse benutzen werden.
Dann m?ssen wir noch die Variablen definieren:
GLOBAL Player AS TPlayer
GLOBAL Shot AS TShot
und dann noch
GLOBAL ButtonB = TRUE
diese liefert uns den Status des B-Buttons bzw der "x"-Taste.
In level00.gbas m?ssen wir noch einige der neuen Variablen initialisieren.
Player.PosX=8
Player.PosY=64
SPR_SHOT=18
// make player sprites
LOADSPRITE "./isdo/gfx/player.png",0
id=1
FOR x=0 TO 3
DRAWRECT 0,0,16,32,COL_TRANSPARENT
DRAWSPRITE 0,-x*16,0
GRABSPRITE id,0,0,16,32
INC id,1
NEXT
Hier laden wir die Grafikdaten f?r unseren Helden. Nr.1+2 sind die Animationsphasen, wenn der Spieler geradeaus fliegt. Nr.3+4 wenn er sich nach oben rechts bewegt. Ihr k?nnt das Ganze ja noch f?r die restlichen Richtungen erweitern.
// make shots
DRAWRECT 0,0,128,32,COL_TRANSPARENT
DRAWSPRITE 0,0,-64
GRABSPRITE 16,0,0,8,8
GRABSPRITE 17,8,0,8,8
GRABSPRITE 18,16,0,8,8
GRABSPRITE 19,24,0,8,8
GRABSPRITE 20,32,0,8,8
GRABSPRITE 24,16,16,16,16
Mit diesen Zeilen erstellen wir die Sprites f?r die Sch?sse.
In der Levelschleife m?ssen wir zuerst den Status des B-Buttons auf TRUE setzen.
ButtonB=TRUE
Das ist wichtig da ansonsten folgendes passiert:
Wir befinden uns ja zuerst im Startmenu. Mit dem B-Button best?tigen wir dann unsere Auswahl. Beginnt nun der Level und der B-Button ist noch gedr?ckt, wird gleich scharf geschossen. Durch setzen von TRUE wird jedoch zuerst gewartet bis der Button losgelassen wird.
Den Z?hler f?r die Sprite-Animation m?ssen wir auch noch erh?hen.
INC Player.Timer,1
GOSUB ShotHANDLER
GOSUB PlayerHANDLER
Mit diesen zwei Unterprogrammen managen wir die Sch?sse und die Heldenanzeige.
Wechseln wir nun zu unserer Library in library.gbas.
Zuerst betrachten wir den PlayerHANDLER.
//=============================================================================
SUB PlayerHANDLER:
//=============================================================================
DRAWSPRITE SPR_PLAYER+(INTEGER((bAND(Player.Timer,3)/2))),Player.PosX,Player.PosY
ENDSUB // PlayerHANDLER
Diseser ist zust?ndig f?r das jeweilige Anzeigen des Spieler-Sprites an der aktuellen Position.
INTEGER((bAND(Player.Timer,3)/2))
gibt je nach Player.Timer 0 oder 1 zur?ck, was der jeweiligen Animationsphase entspricht. In unserem Programm haben wir nur deren 2.
Im KeyHANDLER gibt es auch ?nderungen.
Zuerst m?ssen wir lokale Variablen definieren
LOCAL kr%,kl%,kd%,ku%
diese speichern, ob die jeweilige Richtungstaste gedr?ck wird oder nicht. Dazu erstmal initialisieren.
kr=0;kl=0;kd=0;ku=0
Nun pr?fen wir ob in die jeweilige Richtung gedr?ckt wrid. Falls ja schreiben wir den Wert in die lokale Variable. Gleichzeitig ?ndern wir die aktuelle Position des Spieler-Sprites.
IF KEY(BUTTON_RIGHT)
kr=2
INC Player.PosX,Player.Speed
ENDIF
IF KEY(BUTTON_LEFT)
kl=8
DEC Player.PosX,Player.Speed
ENDIF
IF KEY(BUTTON_DOWN)
kd=4
INC Player.PosY,Player.Speed
ENDIF
IF KEY(BUTTON_UP)
ku=16
DEC Player.PosY,Player.Speed
ENDIF
Anschliessend addieren wir die einzelnen Variablen zu einer Bit-Maske. D.h. wir haben die bin?re Zeichenfolge "00000". Wenn nach rechts gesteuert wird sieht die Maske so aus "00010", wenn nach oben und rechts gesteuert wird so "10010". So ist es auch m?glich abzufragen, ob mehrere Tasten gedr?ckt werden. Die Maske speichern wir in Player.Dir.
Player.Dir=kr+kl+kd+ku
Jetzt kommt etwas un?bliches. SPR_PLAYER ist ja eigentlich eine KONSTANTE SpriteID. Wir benutzen sie hier jedoch ausnahmsweise als Variable und k?nnen somit bei einer Richtungs?nderung mit nur einem Befehl das Basissprite f?r die Animation ver?ndern. Ich hab's hier mal als Beispiel f?r oben rechts gemacht.
SPR_PLAYER=1
SELECT Player.Dir
CASE DIR_RIGHTUP
SPR_PLAYER=3
ENDSELECT
Nun bringen wir unserem Held das Schiessen bei.
// player shoot
IF KEY(BUTTON_B)
IF ButtonB=FALSE
ButtonB=TRUE
GOSUB ShotADD
ENDIF
ELSE
ButtonB=FALSE
ENDIF
Wenn der B_Button oder die "x"-Taste gedr?ckt wird springen wir zur Routine ShootADD welche einen Schuss zu unserer Szene hinzuf?gt.
Zuerst definieren wir einen lokale Z?hlvariable und initialisieren diese mit 0.
LOCAL ix%
ix=0
Dann durchlaufen wir 8x eine Schleife welche f?r jeden m?glichen Schuss eine Pr?fung durchf?hrt.
Loop1:
....
....
GOTO Loop1
ENDIF
Wir pr?fen ob der lokale Z?hler beim letzten Schuss angekommen ist.
IF ix=Shot.Count THEN RETURN
Falls ja, wird kein weiterer Schuss hinzugef?gt.
Anschliessend schauen wir ob der aktuelle Schusseintrag schon belegt ist.
IF Shot.State[ix]=0
Dann ?bergeben wir die Rchtungsmaske und die Startposition vom neuen Schuss.
Shot.Dir[ix]=Player.Dir
Shot.PosX[ix]=Player.PosX+8
Shot.PosY[ix]=Player.PosY+10
Shot.State[ix]=1
Shot.State ist eine Statusvariable die uns die aktuellen Phase des Schusses widergibt.
Im ShootHANDLER definieren wir einige lokale Variablen und durchlaufen dann in einer Schleife wieder alle 8 m?glichen Sch?sse.
//=============================================================================
SUB ShotHANDLER:
//=============================================================================
LOCAL ix%,ev%,x%,y%
FOR ix=0 TO Shot.Count-1
IF Shot.State[ix]
....
....
ENDIF
NEXT
Wir berechnen nun die Position des aktuellen Schusses in unserer Eventmap und lesen deren Wert aus.
x=INTEGER(ScrollX+Shot.PosX[ix]) / 16
y=INTEGER(ScrollY+Shot.PosY[ix]-32) / 16
ev=Event.Map[x*16+y]
Wie wir ja bereits wissen, besteht die Eventmap aus speziellen Attributen. Solch ein Attribut kann zum Beispiel sein, ob an derselben Stelle in der Vordergrundmap sich ein Hindernis (Wand oder ?hnliches) befindet. Praktisch bedeutet dies, dass wir den Schuss beenden sobald er auf eine Wand trifft und nicht einfach durch sie hindurchfliegt.
Trifft der Schuss auf eine Wand geben wir die aktuelle Schussm?glichkeit in der Indexliste mit
IF ev>0 THEN Shot.State[ix]=0
wieder frei.
Je nach Flugrichtung ver?ndern wir die Schussposition, zeichnen das entsprechende Sprite und ?berpr?fen noch, ob der Schuss am Bildrand angekommen ist.
CASE DIR_RIGHTUP
INC Shot.PosX[ix],2
DEC Shot.PosY[ix],2
DRAWSPRITE SPR_SHOT-1,Shot.PosX[ix],Shot.PosY[ix]
IF Shot.PosX[ix]>320
Shot.State[ix]=0
ENDIF
Im nachsten Teil behandeln wir dann die Gegner.
[attachment deleted by admin]