Start · Sprachen · JavaScript · Referenz · Gamepad

Gamepad

Schnittstelle

Stellt einen einzelnen angeschlossenen Controller dar und liefert Tastenzustände, Achsenwerte, ID, Index und Mapping als Momentaufnahme.

seit JavaScript Baseline: alle modernen Browser (seit 2023 weitgeh Kategorie: webapi

Signatur

interface Gamepad

Beschreibung

Das Interface Gamepad gehört zur Gamepad API und steht für einen einzelnen Controller, z. B. ein Xbox- oder PlayStation-Pad, einen Joystick oder ein Lenkrad. Ein Gamepad-Objekt kann man nicht selbst erzeugen. Man erhält es über navigator.getGamepads() oder über die Eigenschaft event.gamepad der Events gamepadconnected und gamepaddisconnected.

Die wichtigsten Eigenschaften (alle schreibgeschützt):

  • id: Textkennung des Geräts, meist Name sowie Hersteller- und Produkt-ID.
  • index: eindeutige Position im Array von getGamepads().
  • connected: ob das Gerät noch verbunden ist.
  • mapping: "standard", wenn der Browser die Tasten auf das Standard-Layout abbildet, sonst "".
  • buttons: Array von GamepadButton-Objekten mit pressed, touched und value (0–1).
  • axes: Array von Zahlen zwischen -1 und 1, z. B. für Analogsticks.
  • timestamp: Zeitpunkt der letzten Aktualisierung, als DOMHighResTimeStamp.
  • vibrationActuator: GamepadHapticActuator für Vibration (Force Feedback).

Die API arbeitet mit Abfragen (Polling), nicht ereignisbasiert. Für Tastendrücke gibt es keine Events. Man liest den Zustand in jedem Frame neu aus, üblicherweise in einer requestAnimationFrame-Schleife. In Chromium-Browsern ist das zurückgegebene Objekt eine Momentaufnahme. Deshalb sollte man navigator.getGamepads() in jedem Frame neu aufrufen und keine alte Referenz aufheben.

Rückgabewert

Typ
Gamepad
Beschreibung
Man erhält es über navigator.getGamepads() (Array aus Gamepad | null) oder über GamepadEvent.gamepad.

Beispiele

Verbundenen Controller erkennen

window.addEventListener('gamepadconnected', (event) => {
  const gp = event.gamepad;
  console.log(`Controller #${gp.index} verbunden: ${gp.id}`);
  console.log(`Tasten: ${gp.buttons.length}, Achsen: ${gp.axes.length}, Mapping: ${gp.mapping || 'unbekannt'}`);
});

window.addEventListener('gamepaddisconnected', (event) => {
  console.log(`Controller #${event.gamepad.index} getrennt`);
});
Controller #0 verbunden: Xbox 360 Controller (XInput STANDARD GAMEPAD) Tasten: 17, Achsen: 4, Mapping: standard

Spielschleife: Stick und Tasten in jedem Frame auslesen

const DEADZONE = 0.15;
const player = { x: 200, y: 200 };

const applyDeadzone = (v) => (Math.abs(v) < DEADZONE ? 0 : v);

const loop = () => {
  // In jedem Frame neu abfragen, denn die Objekte sind Momentaufnahmen
  const [gp] = navigator.getGamepads().filter(Boolean);

  if (gp) {
    player.x += applyDeadzone(gp.axes[0]) * 5; // linker Stick horizontal
    player.y += applyDeadzone(gp.axes[1]) * 5; // linker Stick vertikal

    if (gp.buttons[0]?.pressed) {
      console.log('A / Kreuz gedrückt – Sprung!');
    }
    // Analoge Schultertaste (rechter Trigger), Wert zwischen 0 und 1
    const gas = gp.buttons[7]?.value ?? 0;
    if (gas > 0) console.log(`Gas: ${(gas * 100).toFixed(0)} %`);
  }

  requestAnimationFrame(loop);
};

requestAnimationFrame(loop);
A / Kreuz gedrückt – Sprung! Gas: 62 %

Neue Tastendrücke (Flanken) erkennen

let previous = [];

const poll = () => {
  const gp = navigator.getGamepads()[0];
  if (gp) {
    gp.buttons.forEach((btn, i) => {
      if (btn.pressed && !previous[i]) console.log(`Taste ${i} neu gedrückt`);
    });
    previous = gp.buttons.map((b) => b.pressed);
  }
  requestAnimationFrame(poll);
};
poll();
Taste 3 neu gedrückt

Vibration auslösen

const rumble = async (gp) => {
  if (!gp.vibrationActuator) {
    console.log('Vibration nicht unterstützt');
    return;
  }
  const result = await gp.vibrationActuator.playEffect('dual-rumble', {
    startDelay: 0,
    duration: 300,
    weakMagnitude: 0.5,
    strongMagnitude: 1.0
  });
  console.log(result);
};

window.addEventListener('gamepadconnected', (e) => rumble(e.gamepad));
complete

// Wichtig · Fallstricke

  • Sicherer Kontext: Die API ist nur über HTTPS (oder localhost) verfügbar. Über die Permissions Policy gamepad kann sie z. B. in iframes gesperrt werden.
  • Datenschutz (Fingerprinting): Browser geben Controller erst nach der ersten Benutzereingabe am Gerät preis, also nach einem Tastendruck oder einer Stickbewegung. Vorher liefert getGamepads() nur null-Einträge, und gamepadconnected wird nicht ausgelöst.
  • Momentaufnahme: In Chrome aktualisiert sich ein gespeichertes Gamepad-Objekt nicht. Rufen Sie deshalb navigator.getGamepads() in jedem Frame neu auf. Das Array kann Lücken enthalten (null), daher vorher filtern.
  • Tastenbelegung: Nur bei mapping === "standard" sind die Indizes verlässlich, z. B. 0 = untere Taste und 12–15 = Steuerkreuz. Andernfalls unterscheiden sich Belegung und Anzahl der Achsen je nach Gerät, Browser und Betriebssystem.
  • Totzone (Deadzone): Analogsticks liefern selbst in Ruhestellung selten exakt 0. Legen Sie deshalb immer einen Schwellwert fest.
  • Vibration: vibrationActuator und playEffect() funktionieren nicht überall zuverlässig. In Firefox fehlt die Unterstützung weitgehend, Safari unterstützt sie erst ab neueren Versionen. Der Effekt "trigger-rumble" wird fast nur von Chromium unterstützt.
  • Veraltete Präfix-Varianten wie navigator.webkitGetGamepads sollten nicht mehr verwendet werden.