Wo ist die Tankstelle?
Heute geht es darum, den Spritverbrauch hinzuzufügen. Jede Verwendung der Schubdüsen wird unsere Treibstoffreserve verringern. Sollte alles aufgebraucht sein, dann stürzt das Landungsschiff unweigerlich ab.
Die Tankanzeige
Bisher war der Verbrauch als Text vorgesehen. Ich möchte jetzt aber die Darstellung lieber als Balken am rechten Rand vornehmen. Diesmal allerdings nicht mit dem Zeichensatz, wie beim Zeitbalken fürs Puzzle, sondern mit Sprites. Immerhin haben wir noch drei unbenutzte Sprites zur Verfügung. Daher wurde der bisherige Text für den Verbrauch in „Canyon.charscreen“ entfernt, außerdem habe ich die Optik geringfügig überarbeitet.
Zunächst habe ich die drei benötigten Sprites im Sprite-Editor entworfen. Dazu habe ich eine neue Datei „Fuel.spriteproject“ hinzugefügt. Das Aussehen ist euch freigestellt, ihr solltet nur beachten, dass wir die volle Höhe von drei Sprites, also 63 Zeilen als gesamten Treibstoffvorrat betrachten. Außerdem solltet ihr die drei Sprites von oben nach unten anordnen. Das folgende Bild zeigt meinen Entwurf.
Damit die neuen Sprites bei der Programmerstellung überhaupt geladen werden und wir gleich unsere Treibstoffanzeige auf den Bildschirm bringen können, passt die Anweisungen hinter dem Label spriteSpaceship bitte folgendermaßen an:
;*** Die Sprites !align 63,0 spriteSpaceship !media "Ship.spriteproject",sprite,0,5 spriteFuel !media "Fuel.spriteproject",sprite,0,3
Fügt direkt dahinter noch die folgenden Anweisungen hinzu:
spriteFuelLeft ;sichtbare Sprites für die Treibstoffanzeige !fill 64,0 ;grün !fill 64,0 ;gelb !fill 64,0 ;rot
Wir werden den Treibstoffverbrauch durch das Löschen von Spritezeilen realisieren. Da wir aber für einen neuen Versuch, wieder die kompletten Sprites benötigen, kopieren wir gleich unsere Spritedaten hinter das Label spriteFuelLeft. Dort können wir die Daten dann problemlos löschen und bei Bedarf einfach unsere Musterdaten erneut kopieren. Mit dem Pseudo-OpCode !fill könnt ihr einen Bereich, mit einem festen Wert füllen. Gebt zunächst die Anzahl der Bytes und dann mit einem Komma getrennt, den gewünschten Füllwert an. Natürlich würde hier auch eine !fill 192,0-Anweisung reichen, aber so ist es leichter vorstellbar, wo welches Sprite landet. Die beiden neuen Label spriteFuel und spriteFuelLeft befindet sich bereits durch die vorherigen Anweisungen an einer 64 Byte-Grenze, wir benötigen daher kein zusätzliches !align.
Da wir gerade in der Nähe sind, fügt doch noch zwei neue Variablen z. B. hinter Alive hinzu:
FuelCounter !byte $00 ;Zähler für Treibstoffverbrauch FuelClear !byte $00 ;nächstes Byte, das gelöscht werden soll
FuelCounter steuert die Geschwindigkeit, mit der der Treibstoff verbraucht wird. In FuelClear finden wir das nächste Byte, dass gelöscht werden soll. Außerdem hilft es uns zu erkennen, wann der Treibstoff aufgebraucht ist.
Um unsere Treibstoffanzeige erstmal auf den Bildschirm zu bekommen, sollten wir jetzt die dazu gehörigen Sprites entsprechend einrichten. Dies machen wir in der Funktion initSprites, die Änderungen sind farblich hervorgehoben.
!zone initSprites ;******************************************************************************* ;*** Sprites initialisieren ;******************************************************************************* ;*** Übergabe: - ;******************************************************************************* ;*** Rückgabe: - ;******************************************************************************* ;*** ändert : A, X, SR ;******************************************************************************* initSprites ldx #spriteSpaceship/64 ;Nr. des ersten 64-Byte-Sprite-Blocks stx SPRITEPOINTER0+4 ;Spritedaten zuweisen inx stx SPRITEPOINTER0+0 inx stx SPRITEPOINTER0+2 inx stx SPRITEPOINTER0+3 inx stx SPRITEPOINTER0+1 ldx #spriteFuelLeft/64 ;Position der kopierten Sprites berechnen stx SPRITEPOINTER0+5 ;Daten für Treibstofftank zuweisen inx stx SPRITEPOINTER0+6 inx stx SPRITEPOINTER0+7 lda #COLOR_GREEN ;Farben für Treibstoffsegmente sta VIC_SPRITE5COLOR lda #COLOR_YELLOW sta VIC_SPRITE6COLOR lda #COLOR_PINK sta VIC_SPRITE7COLOR lda #$20 ;X-Position Treibstoff (VIC_SPRITESMAXX gesetzt!) sta VIC_SPRITE5X sta VIC_SPRITE6X sta VIC_SPRITE7X lda #$40 ;Y-Pos. grün sta VIC_SPRITE5Y lda #$40+42 ;Y-Pos. gelb sta VIC_SPRITE6Y lda #$40+84 ;Y-Pos. rot sta VIC_SPRITE7Y jsr updateSprites ;Sprite-Positionen setzen lda #COLOR_BLACK ;Farben der Sprites setzen sta VIC_SPRITE0COLOR lda #COLOR_LIGHTGREY sta VIC_SPRITE4COLOR lda #COLOR_RED sta VIC_SPRITEMULTICOLOR0 lda #COLOR_YELLOW sta VIC_SPRITEMULTICOLOR1 lda #%00001110 ;nur die "Feuer"-Sprites sind MultiColor sta VIC_SPRITEMULTICOLOR lda #%00000000 sta VIC_SPRITEDEEP lda #%11100000 ;Nur die Sprites für die Treibstoffsegmente sta VIC_SPRITEDOUBLEWIDTH ;in der Breite und sta VIC_SPRITEDOUBLEHEIGHT ;Höhe verdoppeln sta VIC_SPRITESMAXX ;So wie das 9. BIT für die X-Position setzen lda #%11110001 ;Schiff & Tank anzeigen sta VIC_SPRITEACTIVE rts ;zurück
Hier ist alles alter Kaffee. Denkt daran, dass die Berechnung der Spritepointer ldx #spriteFuelLeft/64 hier nur klappt, da wir den Grafikspeicher im ersten 16KB-Block belassen haben! Die restlichen Anweisungen setzen nur die Spritepointer, die Positionen und Farben, verdoppeln die Breite und Höhe und schalten die Sprites sichtbar.
Falls ihr das Programm nun starten wollt, denkt dran, dass die Sprites noch nicht kopiert wurden. Wir würden also nichts sehen. Daher schnell mal eine Kopierfunktion gebastelt. Ich habe diese vor checkCollision eingefügt.
!zone initFuel ;******************************************************************************* ;*** Die Treibstoffanzeige initialisieren ;******************************************************************************* ;*** Übergabe: - ;******************************************************************************* ;*** Rückgabe: - ;******************************************************************************* ;*** ändert : A, X, SR ;******************************************************************************* initFuel lda #$00 ;nächstes zu löschendes Byte sta FuelClear ;auf 0 setzen lda #FUELCOUNTINIT ;Treibstoffzähler sta FuelCounter ;initialisieren ldx #3*(63+1) ;3 Sprites zu je 63 Bytes + 1 Füllbyte = 192 ($C0) .loop lda spriteFuel-1,X ;Byte aus der Vorlage holen sta spriteFuelLeft-1,X ;und kopieren dex ;Schleifenzähler verringern bne .loop ;solange größer 0 wiederholen rts ;zurück zum Aufrufer
Wir setzen zu Beginn die Nr. für das nächste Byte, das gelöscht werden soll, auf 0. Dann initialisieren wir den Zähler für den Treibstoffverbrauch mit der neuen Konstanten FUELCOUNTINIT. Anschließend wird das X-Register als Schleifenzähler mit der Anzahl der zu kopierenden Bytes gefüllt. Die drei Sprites haben je 21 Zeilen zu 3 Bytes zzgl. einem Füll-Byte, wir kommen also auf (21 * 3 + 1) * 3 = 192 ($C0) Bytes. Bei .loop kopieren wir dann die Bytes. Da X nie Null wird, verringern wir die Adressen von Quelle und Ziel um 1, damit auch alle Bytes kopiert werden.
Legt nun hinter THRUST_Y die neue Konstante an FUELCOUNTINIT = $08 ;Warteschleife für Spritverbrauch.
Aufrufen müssen wir die eben erstellte Funktion natürlich auch noch, das machen wir in initLander, direkt hinter der Zeile jsr initSprites: ;Sprites initialisieren, mit einem weiteren Sprung: jsr initFuel ;Treibstoffreserve zurücksetzen.
Nun ist es soweit, wir können das Programm zum Test einmal starten…
Da ist sie endlich, die riesen große 😉 Treibstoffanzeige. Natürlich geschieht noch nichts, wir müssen als nächstes dafür sorgen, dass der Treibstoff auch tatsächlich verbraucht wird.
Dazu begeben wir uns in die Funktion checkInput. Jedes Mal, wenn wir die Düsen anzeigen, werden wir den Treibstoffzähler FuelCounter um eins verringern. Fügt dazu hinter jeder der drei bcc-Anweisungen die Zeile dec FuelCounter ;Treibstoffzähler verringern ein. Dadurch erreichen wir, dass der Verbrauch mit jeder aktivierten Schubdüse zunimmt.
Um jetzt den Verbrauch sichtbar zu machen, wollen wir jedes Mal, sobald FuelCounter kleiner als Null ist, eine Zeile in der Treibstoffanzeige entfernen. Dies machen wir einfach in unserer Hauptschleife. Sucht also das Label gameloop und fügt die folgenden Zeilen direkt dahinter ein:
lda FuelCounter ;Treibstoffzähler in den Akku bpl .skip ;solang positiv (>=0) -> .skip clc adc #FUELCOUNTINIT ;sonst, Zähler zurücksetzen sta FuelCounter lda #$00 ;jetzt eine Zeile der Treibstoffanzeige löschen ldx FuelClear ;aktuelle Löschposition ins X-Reg. sta spriteFuelLeft,X ;1. Byte löschen inx ;hochzählen sta spriteFuelLeft,X ;2. Byte löschen inx sta spriteFuelLeft,X ;3. Byte löschen inx stx FuelClear ;nächstes zulöschendes Byte merken .skip
Gleich als Erstes holen wir FuelCounter in den Akku und kontrollieren, ob dieser noch positiv ist, falls ja geht es direkt bei der Kollisionsprüfung (nun hinter .skip) weiter. Ist er aber negativ, dann müssen wir tätig werden. Wir sollten den Counter zurücksetzen, dazu addieren wir die Konstante FUELCOUNTINIT einfach zum Akku und speichern das Ergebnis wieder bei FuelCounter. Um dann eine Zeile im Sprite zu löschen, füllen wir den Akku mit 0 und holen uns das zulöschende Byte aus FuelClear ins X-Register. Wir speichern als nächstes den Akku-Inhalt einfach an der Startadresse, der von uns kopierten Sprites zzgl. dem X-Register. X wird anschließend um eins erhöht. Dies wiederholen wir noch zwei mal und speichern zum Schluß den Wert des X-Registers wieder bei FuelClear.
Probiert ihr das Programm jetzt, dann sieht zunächst alles gut aus, aber erreicht ihr beim Verbrauch den gelben Abschnitt wird ein Versatz sichtbar.
Der Grund ist recht simpel, wir löschen das Sprite zeilenweise, aber ein Sprite hat nur 63 Bytes. Wir müssen das Füll-Byte beachten. Also passt die obige Funktion zwischen dem letzten inx und dem stx FuelClear ;nächstes zulöschendes Byte merken noch etwas an (s. gelb hervorgehobenen Zeilen):
inx txa ;prüfen ob Korrektur wg. 64. Byte and #%00111111 ;nur die unteren sechs Bytes betrachten cmp #%00111111 ;war das eben das 63. Byte bne .skip2 ;wenn nicht -> .skip2 inx ;sonst zur Korrektur Position um 1 erhöhen .skip2 stx FuelClear ;nächstes zulöschendes Byte merken .skip
Wir kopieren das X-Register in den Akku und kontrollieren einfach, ob bereits 63 Bytes kopiert wurden. Falls ja erhöhen wir X nochmal um 1, bevor wir den Wert bei .skip2 speichern.
Jetzt sollte der Verbrauch ohne Umbruch angezeigt werden. Eine letzte Kleinigkeit fehlt aber noch, sobald der gesamte Treibstoff aufgebraucht ist, wollen wir die Steuerung unterbinden. Dies können wir durch drei kleine Zeilen in checkInput erreichen. Fügt diese hinter dem tax am Funktionsbeginn ein.
checkInput lda VIC_SPRITEACTIVE ;alle Flammen für die Düsen and #%11110001 ;ausblenden und tax ;im X-Register merken lda FuelClear ;nächstes zu löschendes Byte in den Akku cmp #3*(63+1) ;prüfen ob bereits alles gelöscht wurde bcs noFire ;falls ja, kann man nicht steuern -> noFire jsr joystickInput ;Aktuellen Joystick-Status holen
Wir kontrollieren einfach, ob bereits alle Zeilen der Treibstoffanzeige gelöscht wurden. Dies ist der Fall, wenn FuelClear 192 oder größer ist. Sobald diese Grenze überschritten wurde, springen wir einfach direkt zu noFire. Das hat zur Folge, dass keine Joystickabfrage mehr stattfindet und das Schiff gnadenlos von der Gravitation ins Verderben gezogen wird.
Wobei es nicht ganz stimmt. Kommt der Spieler mit dem letzten Tropfen zur Landezone, dann kann immer noch eine saubere Landung gelingen. Er darf nur nicht zu schnell aufsetzen.
Jetzt könnt ihr euch an der Landung versuchen. Über FUELCOUNTINIT beeinflusst ihr die Geschwindigkeit des Treibstoffverbrauchs und somit ebenfalls den Schwierigkeitsgrad. Mit meinen beschränkten Fähigkeiten empfinde ich den von mir verwendeten Wert 8 schon äußerst hart.
Wieder eine Etappe geschafft. Level 2 – Die Landung nähert sich nun langsam seinem Ende. Die spielerischen Herausforderungen wurden alle implementiert. Jetzt fehlt nur noch etwas Kosmetik.
Schritt 18 - Landung 008
Wir werden leider auf ein Update von Arthur warten bis wir hiermit weitermachen können, da es manchmal reicht nur ein Zeichen zu ersetzen, und schon meldet CMB Prg Studio lauter invalid branches (zB beq doRasterIRQ_Laser: und beq doRasterIRQ_Laser1:), zB schon nur wenn man die Konstante FUELCOUNTINIT von $08 in $0F umwandelt.
Die Cheap Labels scheint er nicht zu vertragen. 🙁
Ps.: die gleichen Fehler erscheinen auch mit deiner Source Datei wenn man etwas editieren möchte.
Hallo,
auf erste Probleme mit den Cheap-Label bin ich am 27.05.14 schon mal eingegangen -> ‘CBM prg Studio 3.0.0: Probleme‘.
Ich stehe heute schon den ganzen Tag mit Arthur in Kontakt und hoffe es wird in Kürze ein Update geben. Ich hatte auch auf eine zügigere Behebung gehofft, aber Arthur braucht auch eine kleine Auszeit.
Mit der aktuellen Beta 3.1 kann ich jedenfalls
FUELCOUNTINIT
ändern, ohne dass es zu Problemen kommt.Danke für die Info. Ich habe jetzt 3.1 installiert und werde versuchen weiter zu machen. Hoffe es klappt jetzt. 🙂