Scopri come utilizzare l'API Gamepad per portare i tuoi giochi web a un livello superiore.
Il easter egg della pagina offline di Chrome è uno dei segreti più conservati della storia ([citation needed]
,
ma per l'effetto drammatico). Se premi la barra spaziatrice o su un dispositivo mobile
dispositivi, tocca il dinosauro, la pagina offline diventa un gioco arcade utilizzabile. Probabilmente sai già che
non devi andare offline quando hai voglia di giocare: in Chrome puoi semplicemente navigare
per about://dino
oppure, per il nerd che ti circonda, passa a about://network-error/-106
. Ma lo sapevi
che esistono
270 milioni di giochi a tema Dino di Chrome giocati ogni mese?
Un altro aspetto che probabilmente è più utile sapere e di cui potresti non essere a conoscenza è che arcade per giocare con un gamepad. Il supporto del gamepad è stato aggiunto circa un anno fa del momento di questa stesura, commit per Reilly Grant. Come puoi vedere, il gioco, proprio come il resto del Progetto Chromium, è completamente open source. Nella in questo post, voglio mostrarti come usare l'API Gamepad.
Utilizzare l'API Gamepad
Rilevamento delle funzionalità e supporto del browser
L'API Gamepad offre un supporto del browser universalmente eccezionale su entrambi computer desktop e dispositivi mobili. Puoi verificare se l'API Gamepad è supportata utilizzando il seguente snippet:
if ('getGamepads' in navigator) {
// The API is supported!
}
In che modo il browser rappresenta un gamepad
Il browser rappresenta i gamepad come Gamepad
.
di oggetti strutturati. Un Gamepad
ha le seguenti proprietà:
id
: una stringa di identificazione per il gamepad. Questa stringa identifica il brand o lo stile dispositivo gamepad connesso.displayId
: ilVRDisplay.displayId
di associati aVRDisplay
(se pertinente).index
: l'indice del gamepad nel navigatore.connected
: indica se il gamepad è ancora collegato al sistema.hand
: un'enumerazione che definisce quale mano terrà il titolare o quale è più probabile che sia tenuto in.timestamp
: l'ultima volta che sono stati aggiornati i dati di questo gamepad.mapping
: la mappatura dei pulsanti e degli assi in uso per questo dispositivo,"standard"
o"xr-standard"
.pose
: un oggettoGamepadPose
che rappresentano le informazioni sulla posa associate a un controller WebVR.axes
: un array di valori per tutti gli assi del gamepad, normalizzati linearmente nell'intervallo di-1.0
-1.0
.buttons
: un array di stati dei pulsanti per tutti i pulsanti del gamepad.
Tieni presente che i pulsanti possono essere digitali (premuto o non premuto) o analogici (ad esempio, pressione del 78%). Questo
è per questo che i pulsanti vengono segnalati come oggetti GamepadButton
, con i seguenti attributi:
pressed
: lo stato di pressione del pulsante (true
se il pulsante viene premuto efalse
se non viene premuto.touched
: lo stato toccato del pulsante. Se il pulsante è in grado di rilevare il tocco, questo ètrue
se viene toccato il pulsante efalse
negli altri casi.value
: per i pulsanti dotati di un sensore analogico, questa proprietà rappresenta il valore in base al quale è stato premuto, normalizzato linearmente per rientrare nell'intervallo0.0
-1.0
.hapticActuators
: un array contenenteGamepadHapticActuator
ognuno dei quali rappresenta l'hardware di feedback aptico disponibile sul controller.
Un'altra cosa che potresti incontrare, a seconda del browser e del gamepad utilizzato:
è una proprietà vibrationActuator
. Consente due tipi di effetti sonori:
- Dual-Rumble: l'effetto di feedback aptico generato da due attuatori di massa rotanti eccentrici, uno in ogni impugnatura del gamepad.
- Trigger-Rumble: l'effetto di feedback aptico generato da due motori indipendenti, con un motore posizionato in ciascuno dei trigger del gamepad.
La seguente panoramica schematica, presa direttamente dalle specifiche, mostra la mappatura e la disposizione dei pulsanti e degli assi su un gamepad generico.
Notifica quando si connette un gamepad
Per sapere quando è connesso un gamepad, esamina l'evento gamepadconnected
che si attiva sul
Oggetto window
. Quando l'utente collega un gamepad, che può avvenire tramite USB o Bluetooth,
Viene attivato un GamepadEvent
con i dettagli del gamepad in una proprietà gamepad
con nome appropriato.
Di seguito, potete vedere un esempio di un controller Xbox 360 che ero in giro (sì, mi piace
retrò).
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"}
*/
});
Notifica quando un gamepad viene disconnesso
La notifica delle disconnessioni del gamepad avviene analogamente al modo in cui vengono rilevate le connessioni.
Questa volta l'app rimane in ascolto dell'evento gamepaddisconnected
. Nota come nell'esempio seguente
Quando scollego il controller Xbox 360, connected
ora è false
.
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
*/
});
Il gamepad nel ciclo di gioco
Il recupero di un gamepad inizia con una chiamata a navigator.getGamepads()
, che restituisce un array
con Gamepad
elementi. L'array in Chrome ha sempre una lunghezza fissa di quattro elementi. Se pari a zero o inferiore
se sono collegati più di quattro gamepad, un elemento potrebbe essere soltanto null
. Assicurati sempre di controllare tutte le voci
l'array e ricorda che i gamepad "ricordano" e potrebbero non essere sempre presenti
il primo slot disponibile.
// When no gamepads are connected:
navigator.getGamepads();
// (4) [null, null, null, null]
Se uno o più gamepad sono collegati, ma navigator.getGamepads()
segnala comunque null
elementi,
potresti dover "svegliare" ciascun gamepad premendo uno dei pulsanti. Puoi quindi eseguire il polling del gamepad
gli stati nel tuo ciclo di gioco, come mostrato nel seguente codice.
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();
L'attuatore della vibrazione
La proprietà vibrationActuator
restituisce un oggetto GamepadHapticActuator
, che corrisponde a un
configurazione di motori o altri attuatori che possono applicare una forza ai fini della tecnologia aptica
feedback. Gli effetti aptici possono essere riprodotti chiamando Gamepad.vibrationActuator.playEffect()
. L'unico
i tipi di effetto validi sono 'dual-rumble'
e 'trigger-rumble'
.
Effetti Rumble supportati
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.
}
Rumble doppio
Il doppio rumore descrive una configurazione aptica con una un motore a vibrazione di massa rotante eccentrico in ogni impugnatura di un gamepad standard. In questa configurazione, Entrambi i motori sono in grado di far vibrare l'intero gamepad. Le due masse sono disuguagliate, pertanto gli effetti di ciascuno possono essere combinati per creare effetti aptici più complessi. Gli effetti dual-rumble sono definiti da quattro parametri:
duration
: imposta la durata dell'effetto di vibrazione in millisecondi.startDelay
: imposta la durata del ritardo prima dell'avvio della vibrazione.strongMagnitude
eweakMagnitude
: imposta i livelli di intensità della vibrazione per: motori di massa rotanti eccentrici più leggeri, normalizzati nell'intervallo0.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,
});
};
Attiva rumore
Il rumble del trigger è l'effetto di feedback aptico generato da due motori indipendenti, con un motore situato in ciascuno dei trigger del gamepad.
// 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,
});
};
Integrazione con il criterio relativo alle autorizzazioni
La specifica dell'API Gamepad definisce
funzionalità controllata dalle norme identificata dalla
la stringa "gamepad"
. Il valore predefinito di allowlist
è "self"
. I criteri di autorizzazione di un documento determinano
se i contenuti del documento sono autorizzati ad accedere a navigator.getGamepads()
. Se disattivato in
qualsiasi documento, nessun contenuto del documento potrà utilizzare navigator.getGamepads()
, né
l'attivazione degli eventi gamepadconnected
e gamepaddisconnected
.
<iframe src="index.html" allow="gamepad"></iframe>
Demo
Nel seguente esempio è incorporata una demo dei tester dei gamepad. Il codice sorgente è disponibile su Glitch. Prova la demo collegando un Gamepad che utilizza USB o Bluetooth e premi un pulsante o si sposta un asse.
Bonus: gioca a Dino di Chrome su web.dev
Puoi giocare a Dino di Chrome con il tuo gamepad su questo
molto sito. Il codice sorgente è disponibile su GitHub.
Controlla l'implementazione del polling del gamepad in
trex-runner.js
e nota come emula le pressioni dei tasti.
Affinché la demo del dino gamepad di Chrome funzioni, ho ha estrapolato il gioco Dino di Chrome dal progetto principale di Chromium (aggiornando impegno precedente Arnelle Ballane), che lo ha inserito in un sito indipendente, ha esteso i l'implementazione dell'API gamepad esistente con l'aggiunta di effetti per attenuazione automatica e vibrazione, creazione di una visualizzazione a schermo intero e Mehul Satardekar ha contribuito alla modalità Buio implementazione. Buon divertimento!
Link utili
Ringraziamenti
Questo documento è stato esaminato da François Beaufort e Mario Rossi. Le specifiche dell'API Gamepad vengono modificate Steve Agoston James Hollyer e Matt Reynolds. I precedenti editor delle specifiche Brandon Jones, Scott Graham e Ted Mielczarek. La specifica delle estensioni per Gamepad è stata modificata Brandon Jones. Immagine hero di Laura Torrent Puig.