Erstellt: 17. November 2013 (zuletzt geändert: 1. November 2021)

Landung 008

Wo ist die Tankstelle?

C64 Studio

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.

Der überarbeitete Canyon.
Der überarbeitete Canyon.

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.

Die Treibstoffanzeige.
Die Treibstoffanzeige.

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…

Die Treibstoffreserve wird angezeigt.
Die Treibstoffreserve wird angezeigt.

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.

Das sieht noch unschön aus…
Das sieht noch unschön aus…

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.

Das vorläufige Endergebnis.
Das vorläufige Endergebnis.

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.



Schrott!!Naja...Geht so...Ganz gut...SUPER! (3 Bewertungen | Ø 5,00 von 5 | 100,00%)

Loading...


ZurückWeiter

3 Gedanken zu „Landung 008“

  1. 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.

    1. 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.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

Protected by WP Anti Spam