Das Schiff bewegen
Langsam ist es an der Zeit, dass wir etwas Bewegung ins Spiel bringen. Beginnen wir damit, das Schiff mit dem Joystick zu steuern und die Düsen unter „Feuer“ zusetzen.
Da wir den Level erstmal als eigenständiges Spiel entwickeln, setzen wir den Joystick fest auf einen Port. Später kann der gewählte Joystick z. B. über die Zero-Page, von einem Programmodul ans nächste übergeben werden. Wir haben beim Puzzle im Titelbild ja schließlich automatisch den Joystick erkannt.
Fügen wir daher an den Beginn unseres Programms die folgenden zwei Zeilen hinzu (die neuen Zeilen sind gelb hervorgehoben):
main ;*** Start des Hauptprogramms lda #$00 ;erstmal fest den 2. Port sta joystickInput+1 ;für den Joystick setzen jsr initLander ;Level starten
Das Auslesen des Joysticks übernehmen wir vom Puzzle und fügen die bekannte Funktion einfach hinter drawCanyon hinzu.
!zone joystickInput ;******************************************************************************* ;*** Den ausgewählten Joystick abfragen ;******************************************************************************* ;*** Übergabe: CIA1_<PORT> an joystickInput:+1 ;******************************************************************************* ;*** Rückgabe: A = aktueller Status ;*** InputState = aktueller Status ;******************************************************************************* ;*** ändert : A, SR ;******************************************************************************* joystickInput lda CIA1_A ;Aktuellen Status von Joy-1 oder 2 holen ;Nach der Joystick-Wahl speichern wir ;die richtige Adresse direkt hinterm lda sta InputState ;Aktuellen Status merken rts ;zurück
Da wir uns den aktuellen Status des Joysticks in InputState merken, fügt diese Variable hinter SpaceshipPos ein.
InputState !byte $00 ;letzte Joystickeingabe
Jetzt benötigen wir natürlich noch eine Funktion, die die Joystickeingabe verarbeitet. Wir begnügen uns zunächst damit, dass Raumschiff direkt zu bewegen. Es gibt noch keine Beschleunigung oder Anziehungskraft. Beginnen wir mit der nächste Routine hinter joystickInput.
!zone checkInput ;******************************************************************************* ;*** Joystickeingabe prüfen ;******************************************************************************* ;*** Übergabe: - ;******************************************************************************* ;*** Rückgabe: Letzte Eingabe in InputState ;******************************************************************************* ;*** ändert : A, X, Y, SR, inputstate: ;******************************************************************************* checkInput lda VIC_SPRITEACTIVE ;alle Flammen für die Düsen and #%11110001 ;ausblenden und tax ;im X-Register merken
Als erstes holen wir uns die sichtbaren Sprites in den Akku und deaktivieren die drei Sprites für die Feuerschübe. Da wir den Akku gleich brauchen, merken wir uns den eben ermittelten Wert im X-Register.
jsr joystickInput ;aktuellen Joystick-Status holen and #%00011111 ;nur die unteren 5-BIT sind von Interesse eor #%00011111 ;da Low-Aktiv, umkehren beq .exit ;keine Eingabe, dann ENDE
Dann springen wir zur Leseroutine für den Joystick und erhalten so im Akku den aktuellen Status. Da wir nur die unteren 5-BITs benötigen, blenden wir die oberen aus. Die Eingabe ist bekanntermaßen low-aktiv, also kehren wir diese wieder um (somit zeigt eine 1 wieder an, dass eine Eingabe vorliegt).
lsr ;rauf und lsr ;runter benötigen wir nicht lsr ;links? bcc .right ;falls nicht, rechts prüfen tay ;Akku im Y-Reg. retten txa ;sichtbare Sprites (X-Reg.) in den Akku ora #%00001000 ;Feuerschub rechts sichtbar tax ;wieder im X-Reg. merken tya ;Akku zurücksetzen dec SpaceshipPos ;Sprite nach links verschieben
Wir benutzen dieses Mal die Shift-Befehle, um die Eingabe zu überprüfen. Da wir rauf / runter Bewegungen des Joysticks nicht benötigen, verwerfen wir diese einfach durch zwei LSR-Befehle. Der nächste Shift-Befehl prüft, ob der Joystick nach links gedrückt wurde. Schaut euch ggf. nochmal die Grafik der Tastatur-Matrix & Joysticks an. Wie ihr seht, zeigen die beiden unteren Bits an, ob rauf oder runter betätigt wurde. In Bit 2 (denkt dran es ist das dritte, da die Zählung mit 0 beginnt!) finden wir die Eingabe für links. Durch die LSR-Befehle wandert das jeweilige „Richtungs-Bit“ ins Carry-Flag und wir können mit BCC prüfen, ob der Joystick in diese Richtung gedrückt wurde oder nicht. Ist das C-Flag hier gelöscht, dann springen wir direkt zu Prüfung, ob der Stick nach rechts gedrückt wurde. Falls das Carry-Flag aber gesetzt ist, wurde der Joystick nach links gedrückt und wir müssen die Eingabe verarbeiten. Dazu wird der Akku (hier stehen ja die Joystickeingaben, die wir gleich wieder brauchen) ins Y-Reg. kopiert. Dann holen wir die aktiven Sprites aus dem X-Register in den Akku und schalten den Feuerschub an der rechten Raumschiffseite sichtbar. Es ist klar, dass der Schub von rechts erfolgen muss, wenn sich das Schiff nach links bewegen soll. Jetzt kopieren wir den Akku zurück ins X-Register und holen die im Y-Reg. gemerkte Joystickeingabe wieder in den Akku zurück. Abschließend wird noch die X-Position des Schiffs um eins verringert und das Programm läuft weiter zur Prüfung, ob der Stick nach rechts gedrückt wurde. Das mag man jetzt als unnötig erachten, da man den Joystick normalerweise nicht gleichzeitig nach rechts und links drücken kann, aber da wir mit Verschiebe-Befehlen arbeiten müssen wir auf jeden Fall ein LSR ausführen. Das kann dann auch die normale Prüfung für rechts erledigen.
.right lsr ;rechts? bcc .fire ;falls nicht, Feuernknopf prüfen tay ;wieder Akku im Y-Reg. retten txa ;sichtbare Sprites holen ora #%00000100 ;diesmal Feuerschub links aktivieren tax ;wieder im X-Reg. merken tya ;Akku zurückholen inc SpaceshipPos ;Raumschiff nach rechts verschieben
Die Prüfung, ob der Stick nach rechts gedrückt wurde unterscheidet sich nicht wirklich von der eben. Sie sollte daher kein Problem für euch darstellen.
.fire lsr ;Feuerknopf gedrückt? bcc .exit ;falls nicht sind wir fertig txa ;diesmal direkt X in den Akku holen ora #%00000010 ;Feuerschub unten aktivieren tax ;wieder im X-Register merken dec SpaceshipPos+1 ;und Schiff nach oben bewegen
Den Feuerknopf benutzen wir, um die untere Schubdüse zu aktivieren. Da dies die letzte Prüfung ist, brauchen wir die Joystickeingabe im Akku danach nicht mehr und wir können bei einem gedrückten Feuerknopf direkt die sichtbaren Sprites in den Akku holen. Wir müssen den Akku aber für das Ende der Funktion wieder ins X-Register kopieren. Außerdem erhöhen wir die Y-Position des Schiffes um eins. Dann geht es automatisch zum Ende der Funktion.
.exit ;im X-Register stehen die sichtbaren stx VIC_SPRITEACTIVE ;Sprites, die wir jetzt wieder setzen rts ;zurück
Bevor wir die Routine mit RTS verlassen, schreiben wir die im X-Register gespeicherten sichtbaren Sprites wieder ins Register 21 $d015 des VIC-II.
Damit unsere Bewegungen nicht zu schnell ablaufen, müssen wir die diese noch timen. Warum benutzen wir dafür nicht einfach den Rasterzeileninterrupt? Fügen wir ans Ende der zweiten Raster-IRQ-Funktion (direkt vor das .exit) die folgenden beiden gelb hervorgehobenen Zeilen ein:
.exit jsr checkInput ;Joystick verarbeiten jsr updateSprites ;und Sprites positionieren lda #%00000001 sta VIC_IRQSTATUS ;VIC-IRQ bestätigen
Nun ist der Zeitpunkt gekommen, das Programm zu testen. Ihr könnt das Schiff bewegen und die Düsen werden, je nach Richtung, auch unter Feuer gesetzt. Natürlich ist es so noch recht langweilig, das Schiff zu steuern, aber das ändern wir im nächsten Beitrag.
Es gibt allerdings noch ein kleines Problem, um das wir uns kümmern sollten. Achtet mal auf den oberen Teil des Schiffes, wenn ihr es direkt unter dem Lasernetz nach links oder rechts bewegt, kommt es zum unschönen Tearing! Das sollte euch nicht verwundern, immerhin haben wir den Aufruf für die Joystickabfrage checkInput und das Positionieren der Sprites updateSprites direkt ans Ende unserer Raster-Routine für den Laser gesetzt. Der Rasterstrahl ist also genau unter dem Laser und wir bewegen die Sprites. Wir sollten die Bewegung an eine andere Stelle verfrachten, wo sie sich nicht mit dem Rasterstrahl in die Quere kommt. Wie wäre es mit dem ersten Rasterinterrupt, der für den Himmel zuständig ist? Dann befindet sich der Strahl im Rahmen und unser Sprite kommt erst viel später. Kopiert die Zeile jsr updateSprites einfach in die erste IRQ-Routine landerIRQ vor das jmp .exit.
Startet nun das Programm und das Tearing ist verschwunden.
Dass der Laser aus dem Tritt kommt, sobald sich das Sprite weiter nach oben bewegt, soll uns (wie bereits erwähnt) nicht weiter interessieren. Später wird das Landungsschiff schließlich zerstört, sobald es den Laser oder eine Mauer berührt.
Im nächsten Beitrag fügen wir dann etwas Physik hinzu, damit das Spiel langsam Form annimmt.
Schritt 15 - Landung 005