Mein erster Versuch, ein Schiff in einem MMBasic-Spiel zu steuern, lief über INKEY$. Für Menüs und Texteingabe ist das prima, bei einem Spiel ist man damit aber sofort an der Wand. INKEY$ liefert immer nur ein Zeichen aus dem Tastatur-Puffer, eines nach dem anderen. Wer gleichzeitig drehen, Schub geben und schießen will, kommt damit nicht durch.

Die Antwort heißt KEYDOWN

KEYDOWN(0) liefert die Anzahl der gerade gedrückten Tasten, KEYDOWN(1) bis KEYDOWN(4) die Codes der bis zu vier ersten gedrückten Tasten. Das ist genau das, was man für Spielsteuerung braucht.

Mein Schema läuft so: einmal pro Frame lese ich den Status in ein kleines Array, und alle Spielsubs fragen anschließend nur noch dieses Array ab.

DIM INTEGER keys(3)

SUB ReadKeys()
  IF KEYDOWN(0) THEN
    keys(0) = KEYDOWN(1)
    keys(1) = KEYDOWN(2)
    keys(2) = KEYDOWN(3)
    keys(3) = KEYDOWN(4)
  ELSE
    keys(0) = 0: keys(1) = 0: keys(2) = 0: keys(3) = 0
  END IF
END SUB

Damit Code wie IF rotate_links_gedrueckt THEN ... lesbar bleibt, gibt es eine kleine Hilfsfunktion:

FUNCTION IsKeyPressed(key_code) AS INTEGER
  IsKeyPressed = (keys(0) = key_code OR keys(1) = key_code OR keys(2) = key_code OR keys(3) = key_code)
END FUNCTION

In der Spiel-Logik fragt es sich dann sehr direkt, mehrere Tasten gleichzeitig sind kein Problem mehr:

IF IsKeyPressed(KEY_LEFT)  THEN ship_angle = ship_angle - 2
IF IsKeyPressed(KEY_RIGHT) THEN ship_angle = ship_angle + 2
IF IsKeyPressed(KEY_UP)    THEN ApplyThrust()
IF IsKeyPressed(KEY_SPACE) THEN FireShot()

Was mich daran am Anfang Stunden gekostet hat: die Cursor-Tasten sind keine ASCII-Werte. Pfeil hoch ist 128, runter 129, links 130, rechts 131. Bis ich das im Handbuch gefunden hatte, hatte ich mit Multibyte-Strings aus INKEY$ herumprobiert, was natürlich Unsinn war. Vier gleichzeitig gedrückte Tasten ist außerdem das Maximum, was KEYDOWN(1..4) liefert; für ein Spiel reicht das, für Chord-Tastenkombinationen muss man das wissen. Und im Spiel-Loop nutze ich INKEY$ und KEYDOWN nicht parallel. Wenn ich nach KEYDOWN noch ein INKEY$ stehen lasse, bleibt im Tastatur-Puffer alter Kram, und das System wirkt zickig.