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

Landung 004

Das Lasernetz stabilisieren

C64 Studio

Kümmern wir uns endlich darum, dass der Himmel nicht mehr flackert, sobald sich das Sprite dem Lasernetz nähert. Dazu verwenden wir einen stabilen Rasterzeileninterrupt.

Vorausgesetzt wird das Wissen aus den weiterführenden Rasterzeilen-Interrupt Beiträgen: Raster-IRQ: PAL oder NTSC, Raster-IRQ: Timing-Probleme und Raster-IRQ: Endlich stabil!!!.

Um das Problem nachzuvollziehen, achtet bitte darauf, dass SPACESHIP_STARTY noch den Wert = $32 hat. Am besten benutzt ihr einfach den vorangegangenen Beitrag Landung 003 als Ausgangsbasis.

Wie ihr euch als zukünftige Raster-Profis denken könnt, haben wir hier ein Timing-Problem. Um darauf besser reagieren zu können, benutzen wir zwei Raster-IRQs. Einen für den Himmel und den zweiten für den Laser. Für diesen verwenden wir einen stabilen Rasterzeileninterrupt. Also, „Frisch Gesellen, seid zur Hand…

RASTERIRQ_LASER     = $30-2         ;das 'Laser-Raster' 
                                    ;-2 für den stabilen Raster-IRQ

Ändert erstmal RASTERIRQ_LASER, wie oben zu sehen. Da der stabile Raster-IRQ etwas Vorlauf benötigt, startet der Laser-Interrupt nun in Zeile 46 $2e. RASTERIRQ_CANYON kann gelöscht werden, die Konstante benötigen wir nicht mehr.

Da wir uns vom Timer-IRQ nicht mehr stören lassen wollen, fügt noch folgende Zeilen zur Interrupt-Einrichtung hinzu, um diesen zu deaktivieren.
Wie wäre es zwischen sta VIC_CONTROLREG1 und cli.

 lda #%01111111                    ;Timer-IRQ 
 sta CIA1_IRQCONTROL               ;abschalten
 lda CIA1_IRQCONTROL               ;und zur Sicherheit bestätigen

Jetzt entsorgen wir unseren bisherigen Interrupthandler (also die komplette landerIRQ-Routine löschen) und beginnen damit die Funktion komplett neu zu schreiben:

!zone landerIRQ
;*******************************************************************************
;*** Interrupthandler
;***
;*** Der 1. Rasterzeileninterrupt wird hier verarbeitet und setzt den
;*** RAM-Vector für den stabilen Raster-IRQ dann auf doRasterIRQ
;*******************************************************************************
;*** Übergabe: -
;*******************************************************************************
;*** Rückgabe: -
;*******************************************************************************
;*** ändert  : -
;*******************************************************************************
landerIRQ
 lda #COLOR_LIGHTBLUE               ;hellblau in den Akku
 sta VIC_BORDERCOLOR                ;die Rahmenfarbe darauf setzen
 lda #RASTERIRQ_LASER               ;nächsten Raster-IRQ beim Laser
 sta VIC_RASTERROWPOS
 lda #<doRasterIRQ                  ;Adresse des Laser-IRQs in den
 sta JT_IRQVECTOR                   ;RAM-Vector
 lda #>doRasterIRQ                  ;auch das MSB
 sta JT_IRQVECTOR+1
 jmp .exit                          ;...und Interrupt verlassen

Da wir nun getrennte Interrupts verwenden, setzten wir jetzt direkt ohne Prüfung die Farbe für den Himmel, tragen dann die Zeile für den nächsten Raster-IRQ ein und biegen den RAM-Vector auf doRasterIRQ um. Dann springen zum Ende des Interrupts, um ihn zu bestätigen und zu verlassen.

Schon kommen wir zum zweiten Interrupt. Dieser verwendet einen stabilen Raster-IRQ und sorgt somit dafür, dass unser Laser immer an der selben Position beginnt.

!align 255,0
doRasterIRQ
;*** Wenn wir hier landen, sind bereits 38-45 Taktzyklen
;*** in der aktuellen Rasterzeile (46 = $2e = $30-2) vergangen!

;*** Zweiten IRQ einrichten
;*** Da die Zeit bei aktivierten ROM nicht reicht,
;*** können wir den 2. Raster-IRQ erst in der übernächsten Zeile bekommen
 lda #<doubleIRQ                    ;(2 TZ) 2. Raster-IRQ einrichten
 sta JT_IRQVECTOR                   ;(4 TZ)
 lda #>doubleIRQ                    ;(2 TZ)
 sta JT_IRQVECTOR+1                 ;(4 TZ)
 tsx                                ;(2 TZ) Stackpointer im X-Reg. retten
 stx doubleIRQ+1                    ;(4 TZ) und fürs zurückholen sichern!
 nop                                ;(2 TZ)
 nop                                ;(2 TZ)
 nop                                ;(2 TZ)
 lda #%00000001                     ;(2 TZ) 1. Raster-IRQ später bestätigen
                                    ;------
                                    ;26 TZ

;*** Jetzt sind 64-71 Taktzyklen vergangen und wir sind
;*** auf jeden Fall in nächsten Rasterzeile (47)!
;*** Verbraucht wurden 1-8 TZ
 inc VIC_RASTERROWPOS               ;(6 TZ) 2. IRQ in der übernächsten Zeile (48)!!!
                                    ;       $d012 wurde bereits automatisch erhöht
 sta VIC_IRQSTATUS                  ;(4 TZ) IRQ bestätigen
 cli                                ;(2 TZ) Interrupts für den 2. Raster-IRQ
                                    ;       wieder freigeben

;*** Wir befinden uns in Rasterzeile 47 und
;*** haben bisher 13-20 Zyklen verbraucht

;*** etwas Zeit verschwenden...
 ldx #$08                           ;            2 TZ
.loop
 dex                                ;8 * 2 TZ = 16 TZ
 bne .loop                          ;7 * 3 TZ = 21 TZ
                                    ;1 * 2 TZ =  2 TZ
                                    ;          ------
                                    ;           41 TZ

;*** Bis hier sind 54-61 Taktzyklen vergangen, jetzt auf den IRQ warten...
;*** Der nächste Rasterinterrupt wird während dieser NOPs auftreten!
 nop                                ;2 TZ (56)
 nop                                ;2 TZ (58)
 nop                                ;2 TZ (60)
 nop                                ;2 TZ (62)
 nop                                ;2 TZ (64)
 nop                                ;2 TZ (66)

doubleIRQ
;*** Wir sind nun in Rasterzeile 48 und
;*** haben bisher genau 38 oder 39 Taktzyklen benötigt!!
;*** Wir können so sicher sein, da der IRQ während der NOPs auftrat.

;*** Jetzt exakt soviele Taktzyklen 'verschwenden', wie in
;*** dieser Zeile noch zu verarbeiten sind (also 24 oder 25).
 ldx #$00                           ;(2 TZ) Platzhalter für 1. Stackpointer
 txs                                ;(2 TZ) Stackpointer vom 1. IRQ wiederherstellen
 nop                                ;(2 TZ)
 nop                                ;(2 TZ)
 nop                                ;(2 TZ)
 bit $01                            ;(3 TZ)
 ldx VIC_RASTERROWPOS               ;(4 TZ)
 lda LaserFlash                     ;(4 TZ) 'Laserfarbe' schonmal in den Akku   
 cpx VIC_RASTERROWPOS               ;(4 TZ) sind wir noch in Rasterzeile 48?
                                    ;------
                                    ;25 TZ = 63 oder 64 TZ!!!

 beq .laser                         ;(3 TZ) wenn JA einen letzten Takt 'verschwenden'
                                    ;(2 TZ) sonst einfach weiterlaufen...

;*** Wir beginnen also immer exakt nach 3 TZ in der dritten Rasterzeile (49)
;*** nach dem 1. Raster-IRQ (den hatten wir ja in für Zeile 46 festgelegt)

Mit dem !align 255,0 sorgen wir wieder dafür, dass uns keine Page-Grenze das Timing zerschießt. Den Rest kennt ihr aus Raster-IRQ: Endlich stabil!!!, außer bei der Zeile lda LaserFlash und einigen Label, sowie Kommentaren hat sich nichts dramatisch geändert. Der lda verwendet jetzt die absolute Adressierung, also mussten wir darauf achten, dass das Timing noch passt.

Nachdem für Stabilität gesorgt wurde, machen wir uns jetzt endlich an die eigentliche Arbeit und sorgen für das Lasernetz.

.laser
 sta VIC_BORDERCOLOR                ;Rahmenfarbe setzen
 inc LaserFlash                     ;'Farbe' fürs Laser-Raster erhöhen

 ldx #$15                           ;Warteschleifen-Anzahl
 dex                                ;kleine Warteschleife, damit der Laser
 bne *-1                            ;zwei Zeilen 'hoch' ist

 lda #COLOR_ORANGE                  ;hier beginnt auf jeden Fall der Canyon
 sta VIC_BORDERCOLOR                ;also Canyon-Farbe in den Rahmen

 lda #RASTERIRQ_SKY                 ;nächsten Raster-IRQ für den Himmel
 sta VIC_RASTERROWPOS

 lda #<landerIRQ                    ;und den RAM-Vector wieder 
 sta JT_IRQVECTOR                   ;auf die erste Routine setzen
 lda #>landerIRQ
 sta JT_IRQVECTOR+1

.exit
 lda #%00000001
 sta VIC_IRQSTATUS                  ;VIC-IRQ bestätigen
 pla                                ;Register zurückholen
 tay                                ;Y
 pla
 tax                                ;X
 pla                                ;Akku

 rti                                ;IRQ verlassen

Wir beginnen damit, die Hintergrundfarbe auf die vom Laser zu setzen und erhöhen dann für den nächsten Durchlauf die Laserfarbe. Dann verbummeln wir mal wieder etwas Zeit, damit der Laser sich über zwei Rasterzeilen erstreckt.
Danach wird der Rahmen auf die Canyon-Farbe gesetzt, im RAM-Vector wieder die Adresse vom Laser-IRQ hinterlegt und schließlich der IRQ bestätigt und verlassen.

Ein Start zeigt uns, dass der Himmel endlich nicht mehr flackert, auch wenn ihr alle Sprites aktiviert ändert sich daran nichts, oder??

Links gibt es noch ein kleines Problem.
Links gibt es noch ein kleines Problem.

Es gibt einen kleinen Grafikfehler ganz links! Bei bestimmten Kombinationen von Sprites verlieren wir wohl etwas Zeit. Auch hierfür gibt es eine Erklärung, die aber mal wieder auf später vertagt wird. Wir könnten das Problem zwar einfach ignorieren, aber wir lösen es durch eine kleine zusätzliche Prüfung. Ersetzt einfach die bisherige Zeile lda #$15 kurz hinter dem Label .laser durch folgenden Block.

 ldx #$14                           ;Warteschleifen-Anzahl
 lda SpaceshipPos+1                 ;Y-Pos des Raumschiffs in den Akku
 cmp #$32                           ;ist es in Zeile 50 (= $32)?
 bne .skip                          ;nein, dann direkt zur Warteschleife
 dex                                ;sonst, die Schleife etwas verkürzen
 dex
.skip

Wir verkürzen unsere Warteschleife einfach um eins und prüfen dann, ob sich das Raumschiff direkt unter dem Laser befindet. Falls ja verringern wir die Warteschleife um zwei Durchläufe.

Jetzt kommt der Laser nur noch aus dem Tritt, wenn sich das Sprite noch weiter nach oben bewegt. Dass kommt aber nicht vor, da das Raumschiff dann zerstört wird und wir z. B. das Lasernetz deaktivieren und eine Explosion anzeigen.

Das Lasernetz ist endlich stabil. (Screenshot Emu64 Beta 5.0.8 mit Simulation der Bildschirmkrümmung und Unschärfe)
Das Lasernetz ist endlich stabil.

Screenshot Emu64 Beta 5.0.8 mit Simulation der Bildschirmkrümmung und Unschärfe

Wie euch im Source evtl. aufgefallen ist, habe ich hier komplett auf das Anspringen der Timer-IRQ-Routine verzichtet. Da wir diese zur Zeit nicht benötigen, können wir sie auch ganz ignorieren. Außerdem habe ich die Hintergrundfarbe auf normal Grau gesetzt, es war mir sonst doch zu dunkel.


Das wäre es auch schon wieder.

Vielleicht fragt ihr euch jetzt, ob der ganze Aufwand hier wirklich notwendig war. Wir hätten das Landungsschiff doch auch einfach etwas tiefer starten lassen können. Die Wahrscheinlichkeit, dass sich der Spieler später dem Laser nochmal so sehr nähert, dass es zum Anzeigefehler kommt ist dann doch eher unwarscheinlich und ob er im Eifer des Gefechtes die Probleme bemerkt wäre ebenfalls fragwürdig.

Meine zwei Cent:
Als Entwickler sollte es immer der eigene Anspruch sein, alles so gut wie möglich umzusetzen. Man sollte also alle Probleme, die man bemerkt oder die einem mitgeteilt werden, abstellen und nicht einfach davon ausgehen, dass kein Anderer darüber stolpert. Diese Annahme ist in der Regel falsch, irgendwer wird es bemerken.
Also behebt alle Fehler und Probleme die ihr findet, auch wenn ihr Auftreten sehr unwahrscheinlich ist.

Beim nächsten Mal kümmern wir uns endlich um die Steuerung.


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

Loading...


ZurückWeiter

Schreibe einen Kommentar

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

Protected by WP Anti Spam