Hier erfahren Sie, wie Sie Ihre Webspiele mithilfe der Gamepad API optimieren können.
Das Easter Egg der Offlineseite von Chrome ist eines der am schlimmsten gehüteten Geheimnisse der Geschichte ([citation needed]
, aber Behauptung wegen des dramatischen Effekts). Wenn Sie die Leertaste drücken oder auf Mobilgeräten auf den Dinosaurier tippen, wird die Offlineseite zu einem spielbaren Arcade-Spiel. Vielleicht ist Ihnen bewusst, dass Sie zum Spielen nicht offline gehen müssen: In Chrome können Sie einfach zu about://dino
gehen oder, im Namen eines Geeks, zu about://network-error/-106
gehen. Aber wussten Sie auch, dass jeden Monat 270 Millionen Chrome-Dino-Spiele gespielt werden?
![Die Offlineseite von Chrome mit dem Chrome-Dino-Spiel.](https://web.dev/static/articles/gamepad/image/chromes-offline-page-th-3d966d4a2f411.png?authuser=6&hl=de)
Eine weitere Tatsache, die wahrscheinlich nützlicher zu wissen ist, ist die Tatsache, dass Sie im Arcade-Modus das Spiel mit einem Gamepad spielen können. Die Gamepad-Unterstützung wurde zum Zeitpunkt der Erstellung dieses Dokuments vor etwa einem Jahr in einem Commit von Reilly Grant hinzugefügt. Wie Sie sehen, ist das Spiel, wie der Rest des Chromium-Projekts, vollständig Open Source. In diesem Beitrag möchte ich Ihnen die Verwendung der Gamepad API zeigen.
Gamepad API verwenden
Funktionserkennung und Browserunterstützung
Die Gamepad API bietet eine universelle Browserunterstützung sowohl auf Computern als auch auf Mobilgeräten. Mit dem folgenden Snippet können Sie feststellen, ob die Gamepad API unterstützt wird:
if ('getGamepads' in navigator) {
// The API is supported!
}
So stellt der Browser ein Gamepad dar
Der Browser stellt Gamepads als Gamepad
-Objekte dar. Ein Gamepad
hat die folgenden Eigenschaften:
id
: Ein Identifizierungsstring für das Gamepad. Dieser String identifiziert die Marke oder den Stil des verbundenen Gamepad-Geräts.displayId
:VRDisplay.displayId
einer verknüpftenVRDisplay
(falls relevant).index
: Der Index des Gamepads im Navigator.connected
: Gibt an, ob das Gamepad noch mit dem System verbunden ist.hand
: Ein Enum-Wert, der definiert, in welcher Hand der Controller am ehesten gehalten wird.timestamp
: Das letzte Mal, dass die Daten für dieses Gamepad aktualisiert wurden.mapping
: Die Schaltflächen- und Achsenzuordnung, die für dieses Gerät verwendet wird, entweder"standard"
oder"xr-standard"
.pose
: EinGamepadPose
-Objekt, das die Poseninformationen darstellt, die mit einem WebVR-Controller verknüpft sind.axes
: Ein Array von Werten für alle Achsen des Gamepads, linear auf den Bereich von-1.0
–1.0
normalisiert.buttons
: Ein Array mit Tastenstatus für alle Tasten des Gamepads.
Beachte, dass die Schaltflächen digital (drückt oder nicht gedrückt) oder analog (z. B. 78% gedrückt werden) sein können. Aus diesem Grund werden Schaltflächen als GamepadButton
-Objekte mit den folgenden Attributen gemeldet:
pressed
: Der gedrückte Zustand der Schaltfläche (true
, wenn die Schaltfläche gedrückt wird, undfalse
, wenn sie nicht gedrückt wird.touched
: Der berührte Zustand der Schaltfläche. Wenn die Schaltfläche Berührungen erkennen kann, ist diese Eigenschafttrue
, wenn sie berührt wird, und andernfallsfalse
.value
: Bei Schaltflächen mit analogem Sensor stellt diese Eigenschaft den Umfang dar, in dem die Schaltfläche gedrückt wurde, linear auf den Bereich von0.0
–1.0
normalisiert.hapticActuators
: Ein Array mitGamepadHapticActuator
-Objekten, von denen jedes die Hardware für haptisches Feedback darstellt, die auf dem Controller verfügbar ist.
Je nach Browser und Gamepad sehen Sie außerdem möglicherweise ein vibrationActuator
-Attribut. Dies ermöglicht zwei Arten von Rumble-Effekten:
- Dual-Rumble: Der haptische Feedbackeffekt, der von zwei exzentrischen rotierenden Massenantrieben erzeugt wird, jeweils einer in jedem Griff des Gamepads.
- Trigger-Rumble: Der haptische Feedback-Effekt, der von zwei unabhängigen Motoren erzeugt wird, wobei sich ein Motor in jedem der Trigger des Gamepads befindet.
Die folgende schematische Übersicht direkt aus der Spezifikation abgeleitet zeigt die Zuordnung und die Anordnung der Schaltflächen und Achsen auf einem generischen Gamepad.
Benachrichtigung, wenn ein Gamepad verbunden wird
Wenn Sie wissen möchten, wann ein Gamepad verbunden ist, warten Sie auf das gamepadconnected
-Ereignis, das beim window
-Objekt ausgelöst wird. Wenn der Nutzer ein Gamepad anschließt, was entweder über USB oder Bluetooth möglich ist, wird ein GamepadEvent
ausgelöst, der die Details des Gamepads in einem passend benannten gamepad
-Attribut enthält.
Im folgenden Beispiel siehst du ein Beispiel für einen Xbox 360-Controller, den ich herumliegen hatte (ja, ich interessiere mich für Retro-Gaming).
window.addEventListener('gamepadconnected', (event) => {
console.log('✅ 🎮 A gamepad was connected:', event.gamepad);
/*
gamepad: Gamepad
axes: (4) [0, 0, 0, 0]
buttons: (17) [GamepadButton, GamepadButton, GamepadButton, GamepadButton, GamepadButton, GamepadButton, GamepadButton, GamepadButton, GamepadButton, GamepadButton, GamepadButton, GamepadButton, GamepadButton, GamepadButton, GamepadButton, GamepadButton, GamepadButton]
connected: true
id: "Xbox 360 Controller (STANDARD GAMEPAD Vendor: 045e Product: 028e)"
index: 0
mapping: "standard"
timestamp: 6563054.284999998
vibrationActuator: GamepadHapticActuator {type: "dual-rumble"}
*/
});
Benachrichtigung, wenn die Verbindung zu einem Gamepad getrennt wird
Die Benachrichtigung über Gamepad-Unterbrechungen erfolgt analog zur Art und Weise, wie Verbindungen erkannt werden.
Dieses Mal wartet die App auf das Ereignis gamepaddisconnected
. Beachten Sie, dass connected
im folgenden Beispiel jetzt false
ist, wenn ich den Xbox 360-Controller vom Controller trenne.
window.addEventListener('gamepaddisconnected', (event) => {
console.log('❌ 🎮 A gamepad was disconnected:', event.gamepad);
/*
gamepad: Gamepad
axes: (4) [0, 0, 0, 0]
buttons: (17) [GamepadButton, GamepadButton, GamepadButton, GamepadButton, GamepadButton, GamepadButton, GamepadButton, GamepadButton, GamepadButton, GamepadButton, GamepadButton, GamepadButton, GamepadButton, GamepadButton, GamepadButton, GamepadButton, GamepadButton]
connected: false
id: "Xbox 360 Controller (STANDARD GAMEPAD Vendor: 045e Product: 028e)"
index: 0
mapping: "standard"
timestamp: 6563054.284999998
vibrationActuator: null
*/
});
Das Gamepad in der Spielschleife
Das Abrufen eines Gamepads beginnt mit einem Aufruf von navigator.getGamepads()
, wodurch ein Array mit Gamepad
-Elementen zurückgegeben wird. Das Array in Chrome hat immer eine feste Länge von vier Elementen. Wenn null oder weniger als vier Gamepads verbunden sind, kann ein Element auch nur null
sein. Prüfe immer alle Elemente des Arrays. Gamepads „merken“ sich ihren Slot und befinden sich möglicherweise nicht immer am ersten verfügbaren Slot.
// When no gamepads are connected:
navigator.getGamepads();
// (4) [null, null, null, null]
Wenn ein oder mehrere Gamepads verbunden sind, navigator.getGamepads()
aber weiterhin null
Elemente meldet, müssen Sie möglicherweise jedes Gamepad durch Drücken einer der Tasten aktivieren. Anschließend können Sie die Gamepad-Status in Ihrer Spielschleife abfragen, wie im folgenden Code gezeigt.
const pollGamepads = () => {
// Always call `navigator.getGamepads()` inside of
// the game loop, not outside.
const gamepads = navigator.getGamepads();
for (const gamepad of gamepads) {
// Disregard empty slots.
if (!gamepad) {
continue;
}
// Process the gamepad state.
console.log(gamepad);
}
// Call yourself upon the next animation frame.
// (Typically this happens every 60 times per second.)
window.requestAnimationFrame(pollGamepads);
};
// Kick off the initial game loop iteration.
pollGamepads();
Der Vibrationsauslöser
Das Attribut vibrationActuator
gibt ein GamepadHapticActuator
-Objekt zurück, das einer Konfiguration von Motoren oder anderen Bedienelementen entspricht, die eine Kraft für haptisches Feedback anwenden können. Haptische Effekte können durch Aufrufen von Gamepad.vibrationActuator.playEffect()
wiedergegeben werden. Die einzigen gültigen Effekttypen sind 'dual-rumble'
und 'trigger-rumble'
.
Unterstützte Rumpeleffekte
if (gamepad.vibrationActuator.effects.includes('trigger-rumble')) {
// Trigger rumble supported.
} else if (gamepad.vibrationActuator.effects.includes('dual-rumble')) {
// Dual rumble supported.
} else {
// Rumble effects aren't supported.
}
Dual-Rumble
Dual-Rumble beschreibt eine haptische Konfiguration mit einem exzentrischen rotierenden Massenvibrationsmotor in jedem Handle eines Standard-Gamepads. Bei dieser Konfiguration kann jeder Motor das gesamte Gamepad vibrieren. Die beiden Massen sind ungleich, sodass ihre Auswirkungen kombiniert werden können, um komplexere haptische Effekte zu erzeugen. Dual-Rumble-Effekte werden durch vier Parameter definiert:
duration
: Legt die Dauer des Vibrationseffekts in Millisekunden fest.startDelay
: Legt die Dauer der Verzögerung fest, bis die Vibration gestartet wird.strongMagnitude
undweakMagnitude
: Legen Sie die Vibrationsintensität für die schwereren und leichteren exzentrischen rotierenden Massenmotoren fest, normalisiert auf den Bereich0.0
–1.0
.
// This assumes a `Gamepad` as the value of the `gamepad` variable.
const dualRumble = (gamepad, delay = 0, duration = 100, weak = 1.0, strong = 1.0) => {
if (!('vibrationActuator' in gamepad)) {
return;
}
gamepad.vibrationActuator.playEffect('dual-rumble', {
// Start delay in ms.
startDelay: delay,
// Duration in ms.
duration: duration,
// The magnitude of the weak actuator (between 0 and 1).
weakMagnitude: weak,
// The magnitude of the strong actuator (between 0 and 1).
strongMagnitude: strong,
});
};
Trigger-Ruckeln
„Rumpeln“ ist der haptische Feedbackeffekt, der von zwei unabhängigen Motoren erzeugt wird, wobei sich jeweils ein Motor in jedem Trigger des Gamepads befindet.
// This assumes a `Gamepad` as the value of the `gamepad` variable.
const triggerRumble = (gamepad, delay = 0, duration = 100, weak = 1.0, strong = 1.0) => {
if (!('vibrationActuator' in gamepad)) {
return;
}
// Feature detection.
if (!('effects' in gamepad.vibrationActuator) || !gamepad.vibrationActuator.effects.includes('trigger-rumble')) {
return;
}
gamepad.vibrationActuator.playEffect('trigger-rumble', {
// Duration in ms.
duration: duration,
// The left trigger (between 0 and 1).
leftTrigger: leftTrigger,
// The right trigger (between 0 and 1).
rightTrigger: rightTrigger,
});
};
Integration mit Berechtigungsrichtlinie
Die Gamepad API-Spezifikation definiert eine richtliniengesteuerte Funktion, die durch den String "gamepad"
identifiziert wird. Die Standardeinstellung allowlist
ist "self"
. Die Berechtigungsrichtlinie eines Dokuments bestimmt, ob Inhalte in diesem Dokument auf navigator.getGamepads()
zugreifen dürfen. Wenn diese Option in einem Dokument deaktiviert ist, darf kein Inhalt im Dokument navigator.getGamepads()
verwenden und die Ereignisse gamepadconnected
und gamepaddisconnected
werden nicht ausgelöst.
<iframe src="index.html" allow="gamepad"></iframe>
Demo
Im folgenden Beispiel ist eine Gamepad-Tester-Demo eingebettet. Der Quellcode ist auf Glitch verfügbar. Probieren Sie die Demo aus, indem Sie ein Gamepad über USB oder Bluetooth verbinden und eine der Tasten drücken oder eine seiner Achsen bewegen.
Bonus: Chrome Dino auf web.dev spielen
Sie können Chrome Dino mit Ihrem Gamepad auf dieser Website spielen. Der Quellcode ist auf GitHub verfügbar.
Sehen Sie sich die Implementierung von Gamepad-Polling-Funktionen in trex-runner.js
an und sehen Sie sich an, wie Tastendrücke emuliert werden.
Damit die Chrome Dino-Gamepad-Demo funktioniert, habe ich das Chrome-Dino-Spiel aus dem Chromium-Kernprojekt entfernt (eine frühere Version von Arnelle Ballane aktualisiert), es auf einer eigenständigen Website platziert, die vorhandene Gamepad API-Implementierung um Ducking- und Vibrationseffekte erweitert, einen Vollbildmodus erstellt und Mehul Satardekar einen dunklen Modus beigetragen. Viel Spaß beim Spielen!
Nützliche Links
Danksagungen
Dieses Dokument wurde von François Beaufort und Joe Medley geprüft. Die Gamepad API-Spezifikation wird von Steve Agoston, James Hollyer und Matt Reynolds bearbeitet. Die ehemaligen Spezifikationsbearbeiter sind Brandon Jones, Scott Graham und Ted Mielczarek. Die Spezifikation für Gamepad-Erweiterungen wird von Brandon Jones bearbeitet. Hero-Image von Laura Torrent Puig.