Ganz schön anziehend
Da es langweilig und unnütz ist, das Landungsschiff einfach so über den Bildschirm zu bewegen, fügen wir jetzt etwas Physik (ich schäme mich das gleich kommende so zu bezeichnen) hinzu. Basis ist natürlich das Programm aus dem vorherigen Beitrag.
Gravitation
Wie die Erde, besitzt auch PB5-78841 eine Anziehungskraft. Sorgen wir also dafür, dass diese auf unser Schiff einwirkt. Jetzt könnten wir dem Planeten eine Anziehungskraft zuweisen, dem Schiff eine Masse, Reibung, Gegenschub usw. festlegen und ein komplexes Rechenmodell entwickeln, das all dies verarbeitet. Viel Spaß dabei… 😉
Wir halten es da dann doch etwas einfacher. Wird nichts unternommen, dann sinkt das Schiff mit zunehmender Zeit immer schneller. Sobald man den Feuerknopf drückt, wird die untere Schubdüse aktiviert. Um so länger der Knopf gedrückt wird, desto größer wird der Schub und sobald die abwärts Bewegung gestoppt ist, steigt das Schiff.
Wie setzen wir dass nun um?
Um auch sanfte Bewegungen zu erreichen, wäre es schön, wenn wir Sprites auch um 0,2 oder 0,6 Pixel bewegen könnten. Dass geht natürlich nicht, aber wir könnten die Sprite-Position und Geschwindigkeit mit Nachkommazahlen verwalten. Da richtige Fließkommazahlen für unser Vorhaben zu aufwendig sind, bauen wir uns unsere eigenen Kommazahlen. Laßt uns einfach zwei Bytes verwenden, das LSB stellt den Nach- und das MSB den Vorkommateil dar. Dass unsere Zahlen in kein normales Zahlensystem passen, soll uns (im Gegensatz zu den nun mit den Augen rollenden Mathematikern) nicht weiter stören. Es geht schließlich nur darum, die gewünschte Bewegung zu erreichen.
2 * 3 macht 4
Widdewiddewitt und Drei macht Neune
Ich mach mir die Welt
Widdewidde wie sie mir gefällt…
Beginnen wir mit dem Hinzufügen von neuen Konstanten und Variablen. Um die Gravitation, X- und Y-Beschleunigung festzulegen. Richten wir erstmal drei neue Konstanten ein:
GRAVITY = $08 ;Anziehungskraft THRUST_X = $04 ;Schubkraft seitwärts THRUST_Y = $06 ;Schubkraft aufwärts
Ersetzt jetzt noch die bisherige Variable SpaceshipPos durch folgenden Block:
Spaceship_PosX !byte $00 !byte SPACESHIP_STARTX ;X- und Spaceship_PosY !byte $00 !byte SPACESHIP_STARTY ;Y-Position des Landungsschiffs Spaceship_SpeedX !word $00 Spaceship_SpeedY !word $00
Hier haben wir jetzt also unsere „Kommazahlen“. Die Berechnung von Spaceship_Pos erfolgt nun mit Vor- und Nachkommaanteil. Neu hinzugekommen ist noch Spaceship_Speed, damit sorgen wir für die Beschleunigung in die verschiedenen Richtungen. Die Geschwindigkeit initialisieren wir mit 0, die Position wird wie bisher initialisiert, nur dass wir diesmal darauf achten, nur den Vorkommateil zu füllen und den Nachkommateil auf 0 zu setzen.
In der Funktion updateSprites setzen wir jetzt die Position der Sprites nicht mehr einfach, sondern wir berechnen Sie über die aktuellen Geschwindigkeiten aus Spaceship_Speed. Passt dazu die Funktion an die neuen Gegebenheiten an.
!zone updateSprites ;******************************************************************************* ;*** Sprites positionieren ;******************************************************************************* ;*** Übergabe: - ;******************************************************************************* ;*** Sprites positionieren ;******************************************************************************* ;*** Übergabe: - ;******************************************************************************* ;*** Rückgabe: - ;******************************************************************************* ;*** ändert : A, X, SR ;******************************************************************************* updateSprites lda Spaceship_SpeedX ;LSB der X-Geschwindigkeit in den Akku clc ;C-Flag für Addition löschen adc Spaceship_PosX ;zum LSB der X-Pos. addieren sta Spaceship_PosX ;und speichern lda Spaceship_SpeedX+1 ;jetzt das MSB der X-Speed in den Akku adc Spaceship_PosX+1 ;zum MSB der X-Pos. addieren (C wird beachtet) sta Spaceship_PosX+1 ;und speichern tax ;X-Position (nur Vorkommateil) holen stx VIC_SPRITE0X ;für Sprite-0 stx VIC_SPRITE1X ;1 und stx VIC_SPRITE4X ;4 übernehmen inx ;rechtes 'Feuer' inx ;um drei Pixel nach rechts inx ;verschieben stx VIC_SPRITE3X ;und positionieren tax ;nochmal die X-Position holen dex ;und linkes 'Feuer' dex ;um drei Pixel nach links dex ;verschieben stx VIC_SPRITE2X lda Spaceship_SpeedY ;LSB der Y-Geschwindigkeit in den Akku clc ;Carry löschen adc Spaceship_PosY ;LSB der Y-Pos. addieren sta Spaceship_PosY ;und speichern lda Spaceship_SpeedY+1 ;MSB der Y-Geschwindigkeit in den Akku adc Spaceship_PosY+1 ;MSB der Y-Pos. addieren sta Spaceship_PosY+1 ;speichern und sta VIC_SPRITE0Y ;für alle fünf Sprites übernehmen sta VIC_SPRITE1Y sta VIC_SPRITE2Y sta VIC_SPRITE3Y sta VIC_SPRITE4Y rts ;zurück
Wie ihr seht, addieren wir zu Beginn die X-Geschwindigkeit auf die X-Position, speichern die neue Position und setzen die Sprites auf den „Vorkommateil“. Am Ende machen wir das Gleiche mit der Y-Position und -Geschwindigkeit.
Auch die Eingabe-Routine muss natürlich an die neue Logik angepasst werden.
!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 jsr joystickInput ;Aktuellen Joystick-Status holen and #%00011111 ;Nur die unteren 5-BIT sind von Interesse eor #%00011111 ;Da Low-Aktiv, umkehren beq .noFire ;keine Eingabe, dann ENDE 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 sec ;C-Flag für Subtraktion setzen lda Spaceship_SpeedX ;LSB der X-Geschwindigkeit in den Akku sbc #THRUST_X ;X-Beschleunigung abziehen sta Spaceship_SpeedX ;speichern lda Spaceship_SpeedX+1 ;MSB der X-Geschwindigkeit holen sbc #$00 ;ggf. C-Flag addieren sta Spaceship_SpeedX+1 ;und ebenfalls speichern tya ;Akku zurücksetzen .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 clc lda Spaceship_SpeedX ;wie eben, nur dass jetzt adc #THRUST_X ;addiert wird sta Spaceship_SpeedX lda Spaceship_SpeedX+1 adc #$00 sta Spaceship_SpeedX+1 tya ;Akku zurückholen .fire lsr ;Feuerknopf gedrückt? bcc .noFire ;falls nicht Anziehungskraft addieren -> noFire: txa ;diesmal direkt X in den Akku holen ora #%00000010 ;Feuerschub unten aktivieren tax ;wieder im X-Register merken sec lda Spaceship_SpeedY ;kein nennenswerter Unterschied zur sbc #THRUST_Y ;links/rechts Beschleunigung sta Spaceship_SpeedY lda Spaceship_SpeedY+1 sbc #$00 sta Spaceship_SpeedY+1 .exit ;im X-Register stehen die sichtbaren stx VIC_SPRITEACTIVE ;Sprites, die wir jetzt wieder setzen rts ;zurück .noFire ;Falls der Feuerknopf nicht gedrückt ist clc ;addieren wir die Gravitation lda Spaceship_SpeedY ;dass funktioniert wie weiter oben adc #GRAVITY sta Spaceship_SpeedY lda Spaceship_SpeedY+1 adc #$00 sta Spaceship_SpeedY+1 jmp .exit ;zum Ende springen
Statt wie bisher, direkt die X- / Y-Position zu verändern, bestimmen wir jetzt mit der Joystick-Eingabe die Geschwindigkeit in die jeweilige Richtung. Dazu addieren bzw. subtrahieren wir (fast identisch zur Position im vorangegangenen Block) unsere Konstanten für die X- / Y-Beschleunigung bzw. Gravitation zum „Nachkommateil“ und beachten dann noch das C-Flag, um auch den „Vorkommateil“ bei einem Übertrag zu verändern.
Durch die neue Speicherung der Position und der Geschwindigkeit, müssen wir auch initLander anpassen.
!zone initLander ;******************************************************************************* ;*** Leveldaten zurücksetzen ;******************************************************************************* ;*** Übergabe: - ;******************************************************************************* ;*** Rückgabe: - ;******************************************************************************* ;*** ändert : A, X, Y, SR ;******************************************************************************* initLander lda #$00 ;'Nachkommastellen' löschen sta Spaceship_PosX sta Spaceship_PosY sta Spaceship_SpeedX ;Geschwindigkeit löschen sta Spaceship_SpeedX+1 sta Spaceship_SpeedY sta Spaceship_SpeedY+1 lda #SPACESHIP_STARTX ;Startposition setzen sta Spaceship_PosX+1 ;X lda #SPACESHIP_STARTY ;und sta Spaceship_PosY+1 ;Y jsr initSprites ;Sprites initialisieren jsr drawCanyon ;den Canyon zeichnen rts ;zurück
Hier jetzt auch die Vor- und Nachkommastellen für die Position und Geschwindigkeit korrekt initialisieren.
Bevor das Programm gestartet werden kann, bedarf es noch einer letzten kleinen Änderung. Sucht das Label .laser beim Raster-IRQ. Kurz dahinter findet ihr die Stelle lda SpaceShipPos+1, diese muss in lda Spaceship_PosY+1 ;MSB der Y-Pos. des Raumschiffs in den Akku geändert werden.
Jetzt sollte sich das Programm starten lassen und ihr könnt das Landungsschiff mit dezenten Schüben kontrollieren.
Auf einen Screenshot verzichte ich, den Unterschied zum letzten Beitrag erkennt man nur, wenn man das Programm selbst ausführt.
Schritt 16 - Landung 006
Im kommenden Teil sollten wir uns mal um die Kollisionserkennung kümmern, damit es endlich eine Herausforderung für den Spieler gibt. Bis dahin spielt mit den Werten etwas herum und schaut wie sich das Programm verhält.