Mein Textbox-Programm
Verfasst: 13. August 2012, 17:37
Horrido,
ich habe in den vergangenen Monaten ein kleines Programm für den SNES geschrieben und möchte das jetzt hier zum Gucken, Verbessern und Verwenden(?) anbieten. Es ist mein zweites SNES-Programm (das erste beschränkte sich auf das Füllen eines BGs mit Tiles; es war wirklich das erste), und an vielen Stellen zusammengesetzt aus Tutorials, maßgeblich aus welchen von bazz, die ich auf wiki.superfamicom.org gefunden habe.
Inhalt und Funktionen des Programms
- Man kann die Textbox an einer beliebigen Stelle erscheinen lassen (#$FA80 = unten, #$F800 = oben, #F940 = Mitte; was anderes würde ein sehr gurkiges Ergebnis zu Tage fördern)
- Man kann Animationen starten, wie sich die Textbox öffnet und schließt
- Man kann Text in die Textbox schreiben und zwischen zwei Textfarben wechseln
- Man kann einen Zeilenumbruch einfügen
- Man kann die Textbox leeren
- Man kann auf einen Button-Druck warten (A)
- Man kann den Text schneller laufen lassen (B)
- Mittels des Konami-Codes ändert Mario seine Laufrichtung
Das Programm ist so ausgelegt, dass die Sprites sich unabhängig von der Textbox bewegen können, da es in keinem Spiel gut kommt, wenn jegliches Geschehen freezt, nur weil eine Textbox geöffnet ist. Dazu habe ich diese ultra-intelligente Spritebewegung implementiert (die Spritegrafik selbst habe ich aus bazz' Sprite-Tutorial übernimmen, AFAIK ist das aus einem Excite-Bike-Klon für das SatellaView(!?)), die sogar die meiste Zeit mit derselben Geschwindigkeit laufen sollte; wenn es nicht so ist und jemand diesbezüglich Verbesserungsvorschläge hat, wäre ich sehr dankbar dafür.
Das Programm ist auf Englisch (zumindest weitesgehend) kommentiert; ich denke, das ist essentiell, wenn man will, das andere den eigenen Code benutzen.
Ich wollte auch gern versuchen, es so Newbie-freundlich wie möglich zu gestalten, dementsprechend mögen viele Erklärungen überflüssig sein für jemand, der sich mit SNES Programmierung schon mehr als einen Monat befasst hat. Viel hilft viel, im Zweifelsfall besteht immer die Möglichkeit zu überlesen.
To Do
- Fertig kommentieren
- Ich habe beim "Case Handling" eine Übergangslösung eingebaut, für die ich mir eine "JMP Map" bauen wollte. Die JMP Map sollte dann in etwa so aussehen, dass ich nach dem Label am Beginn selbiger eine Liste von JMP-Befehlen habe, und dann, wenn einer dieser Spezialfälle eintritt, er automatisch auf den passenden JMP-Befehl springt (soll heißen: Bei Spezialfall #2 gehe zu: (Adresse von JMP Map)+4 Byte, bei Spezialfall #3 gehe zu: (Adresse von JMP Map)+6 Byte usw. Habe ich bisher nicht eingebaut, weil die Menge der Sonderfälle noch überschaubar ist. Ein Vorgehen nach dem Muster "Ist es das? Nein. Ist es das? Nein. Ist es das?" lässt den 5A22 da noch nicht in die Knie gehen, und außerdeeem... hieße das bei meinen momentanen Kenntnissen mehrere Stunden Trial and Error für nix.
- Ich wollte noch einbauen, dass ich für eine beliebige, vorher festgesetzte Zeichenkette ("Schwert", "Holerö!", "ist zu viel!" o. ä.) nur ein einziges Zeichen in die Textdatei setzen muss. AFAIK wurde selbiges ja in vielen Spielen so programmiert, um Speicherplatz zu sparen. Hatte bisher nur keine Lust dazu (viel Aufwand, wenig Nutzen...?).
- "CloseTextBox" ist de facto nur eine Umkehr von "OpenTextBox" und wurde von mir am Sonntagabend hingekleckert; ich wollt' fertig werden.
Dementsprechend habe ich eine absolut ungalante Lösung für ein ausstehendes Problem genommen: Bei OpenTextBox zählt man den Arbeitsschritt-Counter von #$00 bis #$0A, und bei #$0A ist die Box komplett fertig. Zum Schließen zählt man von #$0A bis #$FF, was mal sowas von unstylish ist, dass... äh...
- In "OpenTextBox" und "CloseTextBox" habe ich jeweils ein Knäuel aus JMP, JML, BNE, BEQ etc., um einige Long-Jumps bzw. Long-Branches (you know what I mean(?)) hinzubekommen, was damals eine Notlösung war, um zu erreichen, was ich wollte. Verbesserungsvorschläge? (Suchbegriff in den Dateien: "Avoid")
Gliederung des Programms / How To
Im Programm die Subroutinen "SubOpenTextBox", "SubCloseTextBox" und "SubTextBox" sind in eigene .inc-Dateien selbigen Namens ausgelagert; die Subroutinen erledigen, wie ihre Namen es erahnen lassen, das Öffnen und Schließen der Textbox, sowie die Verarbeitung der Textdaten (aus einer Binärdatei, in diesem Fall "text.inc"). In der Datei "mainprgm.inc" ist das Hauptprogramm ab dem Zeitpunkt enthalten, ab dem alle Register vorbereitet und alle Daten an die richtige Stelle geladen sind; es beginnt mit dem Befehl, dass Mario sich bewegt, dann dem Befehl, dass sich die Box öffnet etc.
Der Setupteil befindet sich in "textbox.asm", genauso wie die Makros, die die Subroutinen aufrufen und/oder die Variablen für die Subroutinen vorbereiten, und die Nonsense-Funktionen. Nonsense-Funktionen sind: DrawLandscape und DoSomethingWithSprites. Dienen dem Zweck, eine halbwegs spielähnliche Umgebung für mein Programm zu schaffen, mit einem Hintergrund, über (und nicht unter!) dem die Textbox sich öffnen soll, mit Sprites, die sich während der Textbox noch bewegen können sollen (siehe oben), tralala.
Schreiben:
In der Binärdatei stehen:
0C 20 für A
0E 20 für B
10 20 für C
[etc.]
3E 20 für Z
40 20 für Ä
42 20 für Ö
44 20 für Ü
46 20 für ?
48 20 für !
4A 20 für ,
4C 20 für -
4E 20 für ein Leerzeichen.
Sonderfunktionen:
00 C0 für eine neue Zeile
01 C0 für das Leeren der Textbox
02 C0 für das Warten auf Buttondruck
FF C0 für das Beenden der SubTextBox-Subroutine
0C 24 steht für ein A in blauer Schriftfarbe (und logischerweise lassen sich alle anderen Buchstaben und Zeichen so einfärben, wenn man die nachstehende 20 durch eine 24 ersetzt).
Diese "Codes" für die Buchstaben werden eins zu eins in die Tilemap geschrieben, wobei die vorne stehenden zwei Byte die Tile-Nummer angeben, die hintenstehenden die den Priority-Bit setzen (die 2 bei der 20/24 - die Textbox ist auf BG3) und die Nummer der Palette (0 = Palette 0, 4 = Palette 1, siehe zweite graue Box des Unterthemas "Tile Maps & Character Maps" auf dieser Seite).
Restekiste
- Geschrieben und getestet mit WordPad, irgendson Hexeditor (ich glaube HxD), WLA DX, BSNES (aus Kompatibilitätsgründen), ZSNES (aus Geschwindigkeitsgründen) und Super Everdrive/SNES (aus Motivationsgründen)
- Ich habe es geschafft, einen Bug zu produzieren, bei dem das Programm in BSNES und auf dem SNES lief, aber ZSNES zum Abstürzen brachte: Ich habe zweimal etwas vom Stack gepullt, obwohl ich insgesamt nur einmal was draufgeschmissen habe. Sollte ich mir merken, wenn ich irgendwann mal ein SNES-Spiel fertig habe, ist das wohl ein halbwegs funktionierender Kopierschutz.
- Die "OpenTextBox"-Funktion habe ich zuerst komplett ohne Loops gebaut, und erst danach zusammengestaucht. Das hat wahnsinnig viel Zeit gekostet! War aber sicherlich doch die beste Möglichkeit, ansonsten säße ich jetzt vielleicht immer noch am Bugfixen der Funktion.
- Wenn man vergisst, $4200 auf #$80 zu setzen, bewegen sich die Grafiken in ZSNES schon, in BSNES/auf dem SNES nicht.
- Wenn ich einen 16bit-Akkumulator habe und sage "STZ BytegrosseVariable.b", schreibt er #$0000 und nicht, wie gewünscht, #$00. Quintessenz von einer halben Woche auf Fehlersuche. ~_~
So. Ich bin durch. Ich denke, ich habe einiges wichtiges vergessen zu schreiben... aber ich denke, dieser Post ist schon lang genug.
ich habe in den vergangenen Monaten ein kleines Programm für den SNES geschrieben und möchte das jetzt hier zum Gucken, Verbessern und Verwenden(?) anbieten. Es ist mein zweites SNES-Programm (das erste beschränkte sich auf das Füllen eines BGs mit Tiles; es war wirklich das erste), und an vielen Stellen zusammengesetzt aus Tutorials, maßgeblich aus welchen von bazz, die ich auf wiki.superfamicom.org gefunden habe.
Inhalt und Funktionen des Programms
- Man kann die Textbox an einer beliebigen Stelle erscheinen lassen (#$FA80 = unten, #$F800 = oben, #F940 = Mitte; was anderes würde ein sehr gurkiges Ergebnis zu Tage fördern)
- Man kann Animationen starten, wie sich die Textbox öffnet und schließt
- Man kann Text in die Textbox schreiben und zwischen zwei Textfarben wechseln
- Man kann einen Zeilenumbruch einfügen
- Man kann die Textbox leeren
- Man kann auf einen Button-Druck warten (A)
- Man kann den Text schneller laufen lassen (B)
- Mittels des Konami-Codes ändert Mario seine Laufrichtung
Das Programm ist so ausgelegt, dass die Sprites sich unabhängig von der Textbox bewegen können, da es in keinem Spiel gut kommt, wenn jegliches Geschehen freezt, nur weil eine Textbox geöffnet ist. Dazu habe ich diese ultra-intelligente Spritebewegung implementiert (die Spritegrafik selbst habe ich aus bazz' Sprite-Tutorial übernimmen, AFAIK ist das aus einem Excite-Bike-Klon für das SatellaView(!?)), die sogar die meiste Zeit mit derselben Geschwindigkeit laufen sollte; wenn es nicht so ist und jemand diesbezüglich Verbesserungsvorschläge hat, wäre ich sehr dankbar dafür.
Das Programm ist auf Englisch (zumindest weitesgehend) kommentiert; ich denke, das ist essentiell, wenn man will, das andere den eigenen Code benutzen.
To Do
- Fertig kommentieren
- Ich habe beim "Case Handling" eine Übergangslösung eingebaut, für die ich mir eine "JMP Map" bauen wollte. Die JMP Map sollte dann in etwa so aussehen, dass ich nach dem Label am Beginn selbiger eine Liste von JMP-Befehlen habe, und dann, wenn einer dieser Spezialfälle eintritt, er automatisch auf den passenden JMP-Befehl springt (soll heißen: Bei Spezialfall #2 gehe zu: (Adresse von JMP Map)+4 Byte, bei Spezialfall #3 gehe zu: (Adresse von JMP Map)+6 Byte usw. Habe ich bisher nicht eingebaut, weil die Menge der Sonderfälle noch überschaubar ist. Ein Vorgehen nach dem Muster "Ist es das? Nein. Ist es das? Nein. Ist es das?" lässt den 5A22 da noch nicht in die Knie gehen, und außerdeeem... hieße das bei meinen momentanen Kenntnissen mehrere Stunden Trial and Error für nix.
- Ich wollte noch einbauen, dass ich für eine beliebige, vorher festgesetzte Zeichenkette ("Schwert", "Holerö!", "ist zu viel!" o. ä.) nur ein einziges Zeichen in die Textdatei setzen muss. AFAIK wurde selbiges ja in vielen Spielen so programmiert, um Speicherplatz zu sparen. Hatte bisher nur keine Lust dazu (viel Aufwand, wenig Nutzen...?).
- "CloseTextBox" ist de facto nur eine Umkehr von "OpenTextBox" und wurde von mir am Sonntagabend hingekleckert; ich wollt' fertig werden.
- In "OpenTextBox" und "CloseTextBox" habe ich jeweils ein Knäuel aus JMP, JML, BNE, BEQ etc., um einige Long-Jumps bzw. Long-Branches (you know what I mean(?)) hinzubekommen, was damals eine Notlösung war, um zu erreichen, was ich wollte. Verbesserungsvorschläge? (Suchbegriff in den Dateien: "Avoid")
Gliederung des Programms / How To
Im Programm die Subroutinen "SubOpenTextBox", "SubCloseTextBox" und "SubTextBox" sind in eigene .inc-Dateien selbigen Namens ausgelagert; die Subroutinen erledigen, wie ihre Namen es erahnen lassen, das Öffnen und Schließen der Textbox, sowie die Verarbeitung der Textdaten (aus einer Binärdatei, in diesem Fall "text.inc"). In der Datei "mainprgm.inc" ist das Hauptprogramm ab dem Zeitpunkt enthalten, ab dem alle Register vorbereitet und alle Daten an die richtige Stelle geladen sind; es beginnt mit dem Befehl, dass Mario sich bewegt, dann dem Befehl, dass sich die Box öffnet etc.
Der Setupteil befindet sich in "textbox.asm", genauso wie die Makros, die die Subroutinen aufrufen und/oder die Variablen für die Subroutinen vorbereiten, und die Nonsense-Funktionen. Nonsense-Funktionen sind: DrawLandscape und DoSomethingWithSprites. Dienen dem Zweck, eine halbwegs spielähnliche Umgebung für mein Programm zu schaffen, mit einem Hintergrund, über (und nicht unter!) dem die Textbox sich öffnen soll, mit Sprites, die sich während der Textbox noch bewegen können sollen (siehe oben), tralala.
Schreiben:
In der Binärdatei stehen:
0C 20 für A
0E 20 für B
10 20 für C
[etc.]
3E 20 für Z
40 20 für Ä
42 20 für Ö
44 20 für Ü
46 20 für ?
48 20 für !
4A 20 für ,
4C 20 für -
4E 20 für ein Leerzeichen.
Sonderfunktionen:
00 C0 für eine neue Zeile
01 C0 für das Leeren der Textbox
02 C0 für das Warten auf Buttondruck
FF C0 für das Beenden der SubTextBox-Subroutine
0C 24 steht für ein A in blauer Schriftfarbe (und logischerweise lassen sich alle anderen Buchstaben und Zeichen so einfärben, wenn man die nachstehende 20 durch eine 24 ersetzt).
Diese "Codes" für die Buchstaben werden eins zu eins in die Tilemap geschrieben, wobei die vorne stehenden zwei Byte die Tile-Nummer angeben, die hintenstehenden die den Priority-Bit setzen (die 2 bei der 20/24 - die Textbox ist auf BG3) und die Nummer der Palette (0 = Palette 0, 4 = Palette 1, siehe zweite graue Box des Unterthemas "Tile Maps & Character Maps" auf dieser Seite).
Restekiste
- Geschrieben und getestet mit WordPad, irgendson Hexeditor (ich glaube HxD), WLA DX, BSNES (aus Kompatibilitätsgründen), ZSNES (aus Geschwindigkeitsgründen) und Super Everdrive/SNES (aus Motivationsgründen)
- Ich habe es geschafft, einen Bug zu produzieren, bei dem das Programm in BSNES und auf dem SNES lief, aber ZSNES zum Abstürzen brachte: Ich habe zweimal etwas vom Stack gepullt, obwohl ich insgesamt nur einmal was draufgeschmissen habe. Sollte ich mir merken, wenn ich irgendwann mal ein SNES-Spiel fertig habe, ist das wohl ein halbwegs funktionierender Kopierschutz.
- Die "OpenTextBox"-Funktion habe ich zuerst komplett ohne Loops gebaut, und erst danach zusammengestaucht. Das hat wahnsinnig viel Zeit gekostet! War aber sicherlich doch die beste Möglichkeit, ansonsten säße ich jetzt vielleicht immer noch am Bugfixen der Funktion.
- Wenn man vergisst, $4200 auf #$80 zu setzen, bewegen sich die Grafiken in ZSNES schon, in BSNES/auf dem SNES nicht.
- Wenn ich einen 16bit-Akkumulator habe und sage "STZ BytegrosseVariable.b", schreibt er #$0000 und nicht, wie gewünscht, #$00. Quintessenz von einer halben Woche auf Fehlersuche. ~_~
So. Ich bin durch. Ich denke, ich habe einiges wichtiges vergessen zu schreiben... aber ich denke, dieser Post ist schon lang genug.