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.