GLB:Steuerung und Schießen
Aus PandoraWiki
Im 4. Teil werden wir unserem Helden Leben einhauchen und ihm beibringen, wie man schiesst.
Im Beispielcode befinden sich neu die Grafikdaten für unser Spielersprite und die Schüsse isdo/gfx/player.png: http://dl.openhandhelds.org/cgi-bin/pandora.cgi?0,0,0,0,46,29
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 = TRUEdiese 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=TRUEDas ist wichtig da ansonsten folgendes passiert: Wir befinden uns ja zuerst im Startmenü. Mit dem B-Button bestätigen wir dann unsere Auswahl. Beginnt nun das 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
Dieser 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ückt 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 wird. 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
ENDIFWir 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

