Signatur
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 vongetGamepads().connected: ob das Gerät noch verbunden ist.mapping:"standard", wenn der Browser die Tasten auf das Standard-Layout abbildet, sonst"".buttons: Array vonGamepadButton-Objekten mitpressed,touchedundvalue(0–1).axes: Array von Zahlen zwischen -1 und 1, z. B. für Analogsticks.timestamp: Zeitpunkt der letzten Aktualisierung, alsDOMHighResTimeStamp.vibrationActuator:GamepadHapticActuatorfü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
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`);
});
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);
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();
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));
// Wichtig · Fallstricke
- Sicherer Kontext: Die API ist nur über HTTPS (oder
localhost) verfügbar. Über die Permissions Policygamepadkann 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()nurnull-Einträge, undgamepadconnectedwird nicht ausgelöst. - Momentaufnahme: In Chrome aktualisiert sich ein gespeichertes
Gamepad-Objekt nicht. Rufen Sie deshalbnavigator.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:
vibrationActuatorundplayEffect()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.webkitGetGamepadssollten nicht mehr verwendet werden.