Aprende a usar la API de Gamepad para llevar tus juegos web al siguiente nivel.
El huevo de pascua de la página sin conexión de Chrome es uno de los secretos peor guardados de la historia ([citation needed]
,
sino que se realizó una declaración para el efecto dramático). Si presionas la tecla barra espaciadora o, en un dispositivo móvil
dispositivos, presiona el dinosaurio, la página sin conexión se convierte en un juego de arcade. Tal vez sepas que
no es necesario que te desconectes cuando quieres jugar: en Chrome, puedes navegar
a about://dino
, o, para el geek que llevas dentro, navega a about://network-error/-106
. Pero, ¿sabías que
que haya
¿Se juegan 270 millones de juegos de dinosaurios en Chrome todos los meses?
Otro hecho que, sin duda, es más útil conocer y que quizás no conozcas puedes jugarlo con un control de juegos. La compatibilidad con controles de juegos se agregó hace aproximadamente un año como de la época de este escrito en una commit por Reilly Grant. Como puedes ver, el juego proyecto de Chromium está completamente de código abierto. En quiero mostrarte cómo usar la API de Gamepad.
Cómo usar la API de Gamepad
Detección de funciones y compatibilidad con navegadores
La API de Gamepad ofrece una excelente compatibilidad con navegadores a nivel universal computadoras de escritorio y dispositivos móviles. Puedes detectar si la API de Gamepad es compatible con el siguiente fragmento:
if ('getGamepads' in navigator) {
// The API is supported!
}
Cómo el navegador representa un control de juegos
El navegador representa los controles de juegos como Gamepad
.
objetos. Un Gamepad
tiene las siguientes propiedades:
id
: Es una cadena de identificación para el control de juegos. Esta cadena identifica la marca o el estilo de un control de juegos conectado.displayId
: ElVRDisplay.displayId
de unaVRDisplay
asociado (si es relevante).index
: Es el índice del control de juegos en el navegador.connected
: Indica si el control de mando sigue conectado al sistema.hand
: Es una enumeración que define en qué mano se sostiene el control o en qué es más probable que lo sostengan. en el que te etiquetaron.timestamp
: La última vez que se actualizaron los datos de este control de juegos.mapping
: Es el botón y la asignación de ejes que se usan para este dispositivo, ya sea"standard"
o"xr-standard"
pose
: Es un objetoGamepadPose
. que representa la información de pose asociada con un controlador WebVR.axes
: Es un array de valores para todos los ejes del control de juegos, normalizados de forma lineal al rango de Del-1.0
al1.0
buttons
: Es un array de estados de botones para todos los botones del control de juegos.
Ten en cuenta que los botones pueden ser digitales (presionados o no presionados) o analógicos (por ejemplo, un 78% presionado). Esta
Es por eso que los botones se informan como objetos GamepadButton
, con los siguientes atributos:
pressed
: Es el estado presionado del botón (true
si se presiona el botón yfalse
). si no se presiona.touched
: Es el estado en el que se toca el botón. Si el botón puede detectar el tacto, este La propiedad estrue
si se toca el botón yfalse
de lo contrario.value
: para los botones que tienen un sensor analógico, esta propiedad representa la cantidad en la que el valor en el rango de0.0
a1.0
.hapticActuators
: Es un array que contiene.GamepadHapticActuator
y cada uno representa el hardware de respuesta táctil disponible en el control.
Según el navegador y el control de mando que tengas,
puedes encontrar algo más.
es una propiedad de vibrationActuator
. Permite dos tipos de efectos de ruido:
- Doble remolque: el efecto de respuesta táctil generado por dos accionadores de masa excéntricos que giran, uno en cada empuñadura del control de mando.
- Disparador-rumble: El efecto de respuesta táctil generado por dos motores independientes, con uno ubicado en cada uno de los gatillos del control de juegos.
La siguiente descripción esquemática, tomada directamente de las especificaciones muestra la asignación y la disposición de los botones y los ejes en un control de juegos genérico.
Notificación cuando se conecta un control de mando
Para saber cuándo se conecta un control de mando, escucha el evento gamepadconnected
que se activa en el
window
. Cuando el usuario conecta un control de juegos, lo que puede hacerse mediante USB o Bluetooth,
Se activa una GamepadEvent
que tiene los detalles del control de juegos en una propiedad gamepad
con un nombre apropiado.
A continuación, puedes ver un ejemplo de un control de Xbox 360 que tenía por ahí (sí, me interesa
videojuegos retro).
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"}
*/
});
Notificación cuando se desconecta un control de juegos
Las notificaciones de desconexiones del control de mando sucede de forma análoga a la forma en que se detectan las conexiones.
Esta vez, la app estará a la espera del evento gamepaddisconnected
. Observa cómo, en el siguiente ejemplo,
connected
ahora está en false
cuando desenchufa el control de Xbox 360.
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
*/
});
El control de mando en tu bucle de juego
La obtención de un control de juegos comienza con una llamada a navigator.getGamepads()
, que muestra un array.
con Gamepad
elementos. El array de Chrome siempre tiene una longitud fija de cuatro elementos. Si es cero o menos
hay cuatro controles de juegos conectados, un elemento puede ser solo null
. Asegúrate siempre de revisar todos los elementos de
y ten en cuenta que los controles de mando su espacio y es posible que no siempre esté presente
primer espacio disponible.
// When no gamepads are connected:
navigator.getGamepads();
// (4) [null, null, null, null]
Si uno o varios controles de juegos están conectados, pero navigator.getGamepads()
aún informa null
elementos,
quizás debas "activar" cada control de mando presionando cualquiera de los botones. Luego, puedes sondear el control de mando
estados en el bucle de juego, como se muestra en el siguiente código.
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();
El accionador de vibración
La propiedad vibrationActuator
muestra un objeto GamepadHapticActuator
, que corresponde a un
configuración de motores u otros accionadores que pueden aplicar una fuerza para la tecnología táctil
comentarios. Se pueden reproducir los efectos táctiles llamando a Gamepad.vibrationActuator.playEffect()
. El único
Los tipos de efectos válidos son 'dual-rumble'
y 'trigger-rumble'
.
Efectos de ruido compatibles
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.
}
Doble ruido
El doble ruido describe una configuración táctil con un motor de vibración de masa rotativa excéntrico en cada manija de un control de juegos estándar. En esta configuración, cualquiera de los dos motores puede hacer vibrar todo el control de mando. Las dos masas son desiguales, de modo que la sus efectos se pueden combinar para crear efectos táctiles más complejos. Los efectos de doble ruido definido por cuatro parámetros:
duration
: Establece la duración del efecto de vibración en milisegundos.startDelay
: Establece la duración del retraso hasta que se inicia la vibración.strongMagnitude
yweakMagnitude
: Establece los niveles de intensidad de vibración para las aplicaciones motores de masa rotativa excéntrica más ligeras, normalizados en el rango de0.0
a1.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,
});
};
Ruido de activador
El ruido de gatillo es el efecto de respuesta táctil que generan dos motores independientes, con uno ubicado en cada uno de los gatillos del control de mando.
// 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,
});
};
Integración con la Política de Permisos
La especificación de la API de Gamepad define
función controlada por políticas identificada por el
la cadena "gamepad"
. Su allowlist
predeterminado es "self"
. La política de permisos de un documento determina
si algún contenido de ese documento puede acceder a navigator.getGamepads()
. Si se inhabilita en
cualquier documento, su contenido no podrá usar navigator.getGamepads()
ni
se activan los eventos gamepadconnected
y gamepaddisconnected
.
<iframe src="index.html" allow="gamepad"></iframe>
Demostración
En el siguiente ejemplo, se incorpora una demostración de verificador del control de juegos. El código fuente está disponible en Glitch. Prueba la demostración conectando un control de mando a través de USB o Bluetooth y presionar cualquiera de los botones o mover cualquiera de sus eje.
Contenido adicional: Juega al dinosaurio de Chrome en web.dev
Puedes jugar al dinosaurio de Chrome con tu control de juegos en este
en el mismo sitio. El código fuente está disponible en GitHub.
Consulta la implementación del sondeo del control de mando en
trex-runner.js
y observa cómo emula la pulsación de teclas.
Para que la demostración del control de juegos del dinosaurio de Chrome funcione, saqué el juego del dinosaurio de Chrome del proyecto principal de Chromium (actualizar un esfuerzo anterior por Arnelle Ballane), la colocó en un sitio independiente, extendió implementación de la API de mando para juegos existente agregando efectos de atenuación y vibración, creó una pantalla completa y Mehul Satardekar contribuyó con un modo oscuro para implementarlos. ¡Que disfrutes de los videojuegos!
Vínculos útiles
- Especificaciones de la API de Gamepad
- Especificaciones de las extensiones de API de Gamepad
- Repositorio de GitHub
Agradecimientos
Este documento fue revisado por François Beaufort y Joe Medley. El usuario edita la especificación de la API de Gamepad Steve Agoston: James Hollyer y Matt Reynolds. Los antiguos editores de especificaciones Brandon Jones, Scott Graham y Ted Mielczarek. La especificación de extensiones de Gamepad es editada por Brandon González. Hero image de Laura Torrent Puig.