Mein Spiel ist von vorne bis hinten Vektor-Grafik: Asteroiden als Polygonzüge, Schiff als Linien, Schüsse als Pixel, alles weiße Striche auf schwarzem Grund. Pixel-Schrift aus dem TEXT-Befehl wirkte daneben wie ein Aufkleber auf einem Vektor-Bild, und beliebig skalieren ließ sie sich auch nicht. Also habe ich mir eine eigene Schrift gebaut, die ebenfalls aus Linien besteht und damit denselben Stil hat wie alles andere auf dem Schirm.
Schrift als Liniensegmente
Jedes Zeichen ist eine Sammlung von Liniensegmenten in einem 5×7-Raster. Beim Zeichnen werden die Koordinaten mit dem Skalierungsfaktor multipliziert und um den Anker verschoben. Skalierung ist damit kostenlos.
Die Daten lege ich als DATA-Statements ab, ein Eintrag pro Zeichen mit ASCII-Code, Anzahl Linien und den x1,y1,x2,y2-Koordinaten:
font_data:
DATA 32, 0 ' Space
DATA 65, 4, 0,7,0,0, 0,0,5,0, 5,0,5,7, 0,3,5,3 ' A
DATA 66, 7, 0,0,0,7, 0,0,4,0, 4,0,5,1, 5,1,4,3, 4,3,0,3, 4,3,5,5, 5,5,0,7 ' B
DATA 79, 4, 0,0,5,0, 5,0,5,7, 5,7,0,7, 0,7,0,0 ' O
DATA 48, 4, 0,0,5,0, 5,0,5,7, 5,7,0,7, 0,7,0,0 ' 0
DATA -1
Beim Programmstart einmal in zwei Arrays lesen, ASCII-Code als Index:
DIM INTEGER font_lines(127)
DIM FLOAT font_coords(127, 19, 3)
SUB InitVectorFont()
LOCAL INTEGER c, nl, i
RESTORE font_data
DO WHILE 1
READ c
IF c = -1 THEN EXIT DO
READ nl
font_lines(c) = nl
FOR i = 0 TO nl - 1
READ font_coords(c, i, 0), font_coords(c, i, 1), font_coords(c, i, 2), font_coords(c, i, 3)
NEXT i
LOOP
END SUB
Ein Zeichen zeichnen
Linien rausziehen, mit size skalieren, am Anker absetzen, fertig:
SUB DrawVectorChar(char$, x, y, size, col)
LOCAL INTEGER ascii_val, i, num_lines
LOCAL FLOAT x1, y1, x2, y2
ascii_val = ASC(char$)
IF ascii_val < 0 OR ascii_val > 127 THEN EXIT SUB
num_lines = font_lines(ascii_val)
IF num_lines = 0 THEN EXIT SUB
FOR i = 0 TO num_lines - 1
x1 = x + font_coords(ascii_val, i, 0) * size
y1 = y + font_coords(ascii_val, i, 1) * size
x2 = x + font_coords(ascii_val, i, 2) * size
y2 = y + font_coords(ascii_val, i, 3) * size
LINE x1, y1, x2, y2, 1, col
NEXT i
END SUB
Eine String-Routine drumherum, die jedes Zeichen einzeln zeichnet und zwischen Buchstaben einen Abstand lässt:
SUB DrawVectorText(text$, x, y, size, col)
LOCAL INTEGER i
LOCAL FLOAT current_x
current_x = x
FOR i = 1 TO LEN(text$)
DrawVectorChar(MID$(text$, i, 1), current_x, y, size, col)
current_x = current_x + 5 * size + 2 * size
NEXT i
END SUB
Mit size = 1 ist die Schrift 7 Pixel hoch, mit size = 3 21 Pixel, mit size = 5 riesig. Alles aus einer Datenquelle.
Was bei mir hängengeblieben ist: DATA/READ/RESTORE ist in MMBasic ein vollwertiges Werkzeug für Lookup-Tabellen und kein Relikt. Das ASCII-indexierte Array ersetzt jede IF-Kette durch einen einzigen Zugriff. Und die Skalierbarkeit, der eigentliche Grund für den ganzen Aufwand, ist umsonst — nochmal size an die Multiplikation drangehängt, fertig. Das initiale Setup hat etwa eine Stunde gedauert, und danach hatte ich eine Schrift, die mit dem Rest des Spiels denselben Stil teilt und überall gleich aussieht.