Puzzle 001

Für diesen Beitrag wurde das CBM prg Studio verwendet.
weitersagen ...
Tweet about this on TwitterShare on FacebookShare on Google+Share on LinkedIn

CBM prg Studio1. Schritt

Wie erwähnt, betrachten wir den ersten Level zunächst als eigenes Spiel und wir entwickeln ihn Linear. Da mich seit Tagen eine Erkältung plagt, starten wir mit einem einfachen Titelbild und einer simplen Joystickabfrage.

Das Spiel soll uns, wie wir es von sovielen gewohnt sind, mit einen Titelbild begrüßen. Da wir noch keine eigenen Zeichensätze oder hochauflösenden Grafiken beherrschen, beschränken wir uns zunächst einfach auf den Standard-Zeichensatz.

Falls noch nicht geschehen, wäre es jetzt an der Zeit das CBM prg Studio zu öffnen.

Startet ein neues C64 Projekt, am Besten mit dem Namen „LOVE„. Klickt nun mit der rechten Maustaste im Projekt Explorer auf „Screen Designs„, wählt dann „Add new file…„ aus, gebt als Filenamen „Title.sdd„ ein und bestätigt mit OK.

Die neu hinzugefügte Datei.
Die neu hinzugefügte Datei.

Mit einem Doppel-Klick auf die Datei startet ihr den Screen Editor. Auf der rechten Seite findet ihr den „Bildschirm„ des C64 mit 40 Zeichen x 25 Zeilen. Dort könnt ihr jetzt mit der linken Maustaste das gewählte Zeichen aus der Grid- oder Map-Ansicht (s. ganz links) platzieren. Mit der rechten Maustaste löscht ihr evtl. falsch gesetzte Zeichen. Spielt etwas mit den angebotenen Optionen (reverse, draw, select, colours, usw. sind eigentlich selbsterklärend), um euch an den Editor zu gewöhnen und entwerft dann das Titelbild. Beachtet bitte, dass wir den normalen Farbmodus verwenden und ihr nicht! auf Multicolor umschaltet! Wir können also nur die Character Colour verwenden und natürlich Background Colour, die aber nicht gespeichert wird (s. u.). Vergesst nich eure Arbeit zu speichern.

Eurer Titel könnte dann z. B. so aussehen:

Titelbild
Titelbild

Wenn ihr den Screen Editor verlasst und erneut startet seht ihr evtl. wieder blau als Hintergrundfarbe. Das kommt daher, dass die Hintergrundfarben und die des Rahmens nicht Bestandteil der „.sdd„-Datei sind. Wir werden diese Farben später direkt im Programm setzen.

Fangen wir mit dem Programm an, klickt dazu mit der rechten Maustaste auf „Assembly Files„ und wählt „Add new file…„ aus. Als Namen gebt bitte „Puzzle.asm„ ein.

 

Wir legen zu Beginn einige Konstanten fest, wer mag kann natürlich auf die Konstanten verzichten und die jeweiligen Werte direkt im Source eingeben. Ich finde es aber einfacher den Source zu verstehen, wenn man auf etwas wie  cmp #JOY_FIRE  statt  cmp #$16  stößt. Man kann direkt erkennen, worum es an der Stelle geht.

 

Anschließend folgt wieder unsere BASIC-Startzeile, wir wollen das Programm zunächst ja eigenständig entwickeln. Hinter  main:  befindet sich das bisher sehr kurze Hauptprogramm  ;-).

 

Wie angedroht, setze ich voraus, dass ihr die Mnemonics kennt und werde hier jetzt nicht mehr jede Zeile einzeln besprechen. In den ersten Sourcen kommentiere ich aber noch relativ viel und erkläre die Funktion dann auch nochmal im Beitrag.
Sind Punkte unklar, umständlich, verquast oder gar falsch erklärt, dann scheut bitte nicht davor zurück mir dies mitzuteilen (z. B. über den Feedback-Button ganz links).

Machen wir weiter und hangeln uns durch die einzelnen Funktionen. Beginnen wir mit  showscreen_Title:  immerhin ist dies die einzige, die das Hauptprogramm zur Zeit aufruft.

 

Die Funktion  drawScreen_Title: dient dazu unseren Titelbildschirm anzuzeigen und auf die Wahl des Joysticks zu warten. Das ist schon etwas ungewöhnlich, die Spiele von damals haben meistens vorausgesetzt, dass sich der Joystick im vorgegebenen Port befand, sie ermöglichten keine automatische Erkennung.

Zunächst wird die Farbe schwarz in den Akku geholt und dann in die entsprechenden VIC-Register für Rahmen- und Hintergrundfarbe geschrieben. Wer andere Farben möchte, muss das hier ändern. Wie vorhin erwähnt, werden diese Infos nicht über den Screen Designer gespeichert.
Anschließend löschen wir zur Sicherheit den aktuell gewählten Joystick, indem wir  INPUT_NONE nach inputDevice:  schreiben.
Dann holen wir die Adresse des gewünschten Bildschirmdesigns ins X- und Y-Register und rufen das Unterprogramm  drawscreen:  auf, um das Bild auf dem Bildschirm anzuzeigen.
Zurück von der Anzeige, warten wir dann solange, bis sich der Spieler für einen Joystick entschieden hat.

 

 

Die Funktion drawScreen: ermöglicht es uns ein beliebiges mit dem Screen Designer vom CBM prg Studio erstelltes ‚Bild‚ auszugeben. Quelle und Ziel sind dabei über die Zero-Page frei einstellbar, hier ist das Ziel aber fest, da es über Konstanten gesetzt wird. Da wir hier in unserem Spiel zum ersten Mal auf die Zero-Page zugreifen, möchte ich die Gelegenheit nutzen und darauf hinweisen, dass wir jetzt intensiven Gebrauch von der Zero-Page machen. Wie ihr bei den Mnemonics seht, sind die Befehle mit Zero-Page-Adressierung kürzer und schneller, als ihre ‚absoluten‚ Gegenstücke. Die erste Hälfte der Zero-Page wird hauptsächlich von BASIC benutzt (mit Ausnahme der „berühmten„ Adressen $00 / $01). Wir beginnen bei $02 mit unserer Belegung der Zero-Page. Es ist absehbar, dass ein Rücksprung zum BASIC irgendwann in einem Fehler endet, immerhin zerstören wir die dazugehörigen Zero-Page-Bereiche. Aber die wenigen freien BYTES auf der Zero-Page werden uns auf Dauer nicht reichen.

Nun wieder zur Funktion…

Zunächst speichern wir die im X- und Y-Register übergebene Quell-Adresse auf der Zero-Page.
Da der Screen 40*25 Zeichen hat, müssen wir zur übergebenen Startadresse der Farben 1000 addieren, um den Beginn der Zeichen zu erhalten, der Screen Designer speichert zunächst die 1000 Farbinformationen, danach kommen die Zeichen. Wir kopieren daher X (hier befindet sich das LSB) in den Akku, löschen das Carry-Flag und addieren das LSB von 1000, also #$E8. Das Ergebnis fürs LSB merken wir uns direkt auf der Zero-Page. Dann kopieren wir Y (das MSB) in den Akku und addieren hierzu das MSB von 1000, was #$03 entspricht. Kam es bei der ersten Addition (die mit dem LSB) zu einem Übertrag, dann wird dieser dank  adc  mit addiert. Auch das errechnete MSB wird in die Zero-Page geschrieben.
Sobald wir die Adresse für die Zeichen haben, setzt wir das Ziel für Zeichen und Farben zurück. Diese werden in der Kopierschleife verändert, also müssen wir erstmal wieder für die richtigen Ausgangswerte sorgen. Hier könnte man ansetzen, wenn man unterschiedliche Zieladressen verwenden möchte, wir benutzen einfach die Standardwerte, für die wir zu Beginn als Konstanten festgelegt haben.
Bevor das eigentliche Kopieren beginnt, müssen wir das Y-Register auf null setzten (warum sehen wir gleich) und tragen ins X-Register die Anzahl der zu kopierenden Pages ein. Wir benötigen vier Pages, da wir 1000 BYTES kopieren wollen (3*256 + 232 BYTES). Da wir später mit  bpl  prüfen, nehmen wir hier eine 3 (die Null hat zwar kein Vorzeichen, wird beim  bpl  aber als ‚positiv‚ gewertet – sie ist ja auch nicht negativ).
Hinter dem nächsten Label  drawscreen_CopyLoop: (in unserer Hauptschleife wird für jede weitere Page hierhin zurückgesprungen) sehen jetzt den Grund, weshalb eben Y = 0 gesetzt werden musste. Beim Schleifenanfang prüfen wir, ob wir bei der letzten Page angelangt sind. Wir zählen X zwar 3, 2, 1, 0 runter, kopieren aber in der Reihenfolge Page 1, 2, 3 und 4. Da jede Page 256 Zeichen beinhaltet und wir mit Y = 0 beginnen, um diese 256 Zeichen zu kopieren, müssen wir bei der letzten Page darauf achten, dass ja nach 1000 Zeichen Schluß ist. Also kopieren wir beim letzten Durchlauf nur noch 232 Zeichen. Dazu kopieren wir zunächst das Zeichen und die Farbe von Y = 0 (die beiden lda  /  sta  Befehle direkt hinter  bne drawscreen_LDAChar: ) und setzten dann mit  ldy #$FF-#$18 Y für den Rest 231.
Die haupt Kopierarbeit wird bei  drawscreen_LDAChar:  erledigt. Dort holen wir uns erstmal das Zeichen von der Quell-Adresse und speichern es an der Ziel-Adresse, das Gleiche machen wir für die Farbe. Wir verwenden hier die Y-nach-indizierte Adressierung. Y wird dabei für die Pages 1 bis 3 immer von 0 herunter gezählt. Da das  dey  vor der  bne  Prüfung geschieht, kippt beim ersten Mal Y von #$00 auf #$FF und wir kopieren also 256 Zeichen. Dadurch wird Y auch automatisch wieder auf null gestellt und wir müssen das für die nächsten Pages nicht manuell erledigen.
Wurden alle BYTES der Page kopiert, dann erhöhen wir die Quell- und Ziel-Adressen für Zeichen und Farben auf der Zero-Page, so dass die nächste Page verwendet wird. Dazu addieren wir einfach 1 zu allen MSBs der betroffenen Adressen.
Zum Schluß wird noch X um eins verringert und solangen es nicht negativ ist, kopieren wir die nächste Seite.

 

Nach der Beendigung dieser etwas größeren Funktion, laden wir wieder in  showScreen_Title:  und warten auf die Wahl des Joysticks.

 

Jetzt ziehe ich die kleine Funktion  joystickInput:  vor, die erst gleich von der nächsten Funktion verwendet wird.

Wie ihr seht ist diese Funktion wirklich sehr kurz, wir holen einfach den aktuellen Wert des CIA1_<Port> – Registers in den Akku und speichern ihn unter inputState:. Etwas Ähnliches kann man bei der Tastatur-Matrix sehen, dort finden wir auch die entsprechenden Werte für die Joystickpositionen. Die obige Routine hat noch ein kleines Problem, man kann auch mit der Tastatur den Feuerknopf auslösen. Drückt ihr z. B. <SPACE> wird das auch als Feuer erkannt. Darum kümmern wir uns aber in einem späteren Beitrag, sobald wir den Joystick komplett abfragen, für den Moment soll das so reichen.

Den Grund weshalb ich CIA1_Port geschrieben haben, sehen wir sofort in der nächsten Funktion:

In der Funktion  selectInputDevice:  prüfen wir, ob der Spieler den Feuerknopf von Joystick-1 oder 2 gedrückt hat. Um festzulegen mit welchem Joystick er spielen möchte. Wurde der Feuerknopf betätigt, dann speichern wir den gewählten Joystick in  inputDevice:  und warten bis der Feuerknopf losgelassen wurde.
Schauen wir uns die Prüfung mal für den Joystick in Port-2 an:
Wir holen zunächst das LSB vom CIA1_A in den Akku und speichern diesen Wert in der Funktion  joystickInput:  direkt hinter dem lda -Befehl.
So etwas gilt heute als Todsünde, bzw. ist nicht mehr machbar: Ein Programm, dass sich selbst verändert. Da die heutigen Prozessoren einen Cache besitzen kann man diese Technik kaum noch anwenden, außerdem unterscheidet z. B. Windows zwischen Programm- und Anwendungsspeicher. Als letztes wissen wir unter Windows  auch gar nicht mehr wo und wie unserer Programm im Speicher liegt.
Aber auf dem C64 ist alles anders und wir können diese Technik verwenden. Wir ändern hier also abhängig von der Wahl des Spielers die Adresse des benötigten CIA1-Ports um den Joystick abzufragen. Nach dem Ändern springen wir zu  joystickInput:  und prüfen dann, ob der Feuerknopf gedrückt wurde. Da  joystickInput: den aktuellen Status in den Akku geholt hat, bevor dieser unter  inputDevice:  abgelegt wurde, müssen wir zur Prüfung nur noch ein  and #JOY_FIRE  einsetzen. Ist das Ergebnis null, ist der Feuerknopf vom Joystick in Port-2 nicht gedrückt und wir springen zu Prüfung von Port-1. Ist er aber gedrückt, dann speichern wir den gewählten Port zur Sicherheit unter  inputDevice:  und warten abschließend solange, bis der Knopf wieder losgelassen wurde. Jetzt ist in  joystickInput:  hinter dem  lda  auch dauerhauft der richtige CIA1-Port für die weiteren Abfragen gespeichert.

 

Unser Programm wird nach der Joystick-Wahl wieder zurück zum BASIC springen. Das ist wie erwähnt nicht ganz unproblematisch, da wir die Zero-Page geändert haben, sollte hier aber noch funktionieren.

Zum Schluß folgen noch unsere Speicherstellen für den gewählten Joystick, die letzte Eingabe und unserer Titelbild.

Neu sollte für uns nur noch die Zeile  incbin "title.sdd",1,1  sein. Hiermit weisen wir den Assembler an, hinter dem Label  screentitel:  den Inhalt der „titel.sdd„ einzufügen. Wir könnten auch die Daten vom Screen Designer direkt als BYTES einfügen. Das hat aber den Nachteil, dass wir bei jeder Änderung die alten Werte löschen und die neuen einfügen müssen.

Ich möchte nochmal darauf hinweisen, dass ich auch erst wieder mit der Programmierung des C64 begonnen habe, daher kann (und wird) es früher oder später passieren, dass etwas was auf den ersten Blick klappt, sich später als unpraktisch oder gar falsch herausstellt und somit geändert werden muss.

Laßt mich das mal an zwei Beispielen aus diesem Abschnitt erklären.

  • Die Joystickabfrage wird von uns ‚manuell‚ vorgenommen. Wir müssen also daran denken zur Funktion zu springen. Evtl. wäre es besser diese in relmäßigen Abständen ‚automatisch‚ vorzunehmen, erst recht wenn man z. B. feststellen muss wie lange ein Knopf bereits gedrückt ist. Dazu könnte man einen Interrupt verwenden, aber das kennen wir ja noch nicht.
  • Unser Titelbild verschlingt horrende viel Speicher. Wenn wir so weiter machen reichen die 64KB bald nicht mehr aus. Jedes Bild benötigt 2*40*25 = 2000 Bytes, also knapp 2KB! Schauen wir uns aber das Bild mal an, dann sehen wir, dass das ‚Nichts‚ überwiegt. Wir müssen uns also überlegen, wie wir den Speicherbedarf reduzieren können. Das soll uns beim Puzzle-Spiel aber noch nicht beschäftigen. Neben dem Startbild brauchen wir ja nur noch unser eigentliches Spielfeld.

So das war der erste Schritt, wie angekündigt könnt ihr das Programm im Java Emulator starten (wie erwähnt der Emulator zickt sehr, wenn ein Programm per URL gestartet werden soll, daher findet ihr unten auf der Emulator-Seite eine Tabelle mit den Startlinks, die besser funktionieren) und auch herunterladen.

Im ZIP findet ihr das Projekt, eine .prg und .d64 Datei.

OK, ich gebe es ja zu, dass ist jetzt nicht sonderlich spektakulär gewesen, aber irgendwo müssen wir ja beginnen. Im nächsten Beitrag verwenden wir dann die ersten Sprites.



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

Loading...


 

<<< zurück | weiter >>>

 

weitersagen ...
Tweet about this on TwitterShare on FacebookShare on Google+Share on LinkedIn

Schreibe einen Kommentar


Beachtet bitte, dass ich eure Kommentare erst manuell freigegeben muß, bevor sie auf der Seite erscheinen! Da ich nicht pausenlos am Rechner sitze, kann es schon mal etwas dauern, bis ein Kommentar für alle sichtbar ist.

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

Protected by WP Anti Spam