Utilizzo dell'API gamepad HTML5 per aggiungere supporto controller ai giochi browser

Poiché i giochi basati sul web diventano più popolari, uno dei più grandi punti di attacco per i giocatori è il controllo degli input. Mentre i miei primi giochi FPS erano puramente basati su mouse e tastiera, ora sono molto più abituato a un controller per console appropriato che preferirei usarlo per tutto, inclusi i giochi basati sul web. 

Fortunatamente, l'API del gamepad HTML5 esiste per consentire agli sviluppatori web l'accesso programmatico ai controller di gioco. Sfortunatamente, sebbene questa API sia in circolazione da molto tempo, solo ora, lentamente, si passa alle versioni più recenti dei browser desktop. Ha languito a lungo in una build di Firefox (non una build più in alto, nessuno ogni notte build) ed è stato problematico in Chrome. Ora è, beh, non perfetto, ma leggermente meno problematico ed in realtà piuttosto facile da usare. 

In questo articolo, discuterò le varie funzionalità dell'API, come farlo funzionare sia in Firefox che in Chrome, e mostrare un gioco reale (se semplice) e quanto sia facile aggiungere il supporto per il gamepad ad esso.

Le basi

L'API del gamepad comprende le seguenti funzionalità:

  • La capacità di ascoltare Collegare e disconnect eventi.
  • La capacità di riconoscere più gamepad. (In teoria, è possibile collegare tanti gamepad quante sono le porte USB.)
  • La possibilità di ispezionare questi gamepad e riconoscere quanti assi hanno (joystick), quanti pulsanti hanno (ultimamente hai giocato a una moderna console di gioco?) E in che stato ciascuno di questi singoli elementi si trova.

Iniziamo discutendo su come è possibile rilevare il supporto per un gamepad ad alto livello. 

Sia Firefox che Chrome supportano un metodo navigatore, getGamepads (), che restituisce una matrice di tutti i dispositivi collegati al gamepad. Possiamo utilizzarlo come un semplice metodo per rilevare se l'API Gamepad è presente. Ecco una semplice funzione per quel controllo:

function canGame () return "getGamepads" nel navigatore; 

Fin qui tutto bene. Ora per la parte funky. L'API Gamepad supporta gli eventi che rilevano quando un gamepad è connesso e disconnesso. Ma cosa succede se l'utente ha già un gamepad collegato al proprio laptop quando ha colpito la tua pagina? Normalmente, la pagina web aspetterà che l'utente faccia qualcosa, davvero qualcosa, con il gamepad reale. Ciò significa che dobbiamo fornire un tipo di messaggio all'utente che gli faccia sapere che è necessario "svegliare" il supporto per il gamepad se è connesso. Potresti dire loro di premere qualsiasi tasto o muovere un bastone. 

Per rendere le cose ancora più interessanti, questo controllo particolare non sembra essere necessario quando ricarichi la pagina. Scoprirai che una volta che hai usato l'API Gamepad su una pagina e poi la ricarichi, la pagina riconosce questo fatto e lo considera automaticamente connesso.

Ma aspetta, migliora. Chrome non supporta gli eventi connessi (o scollegati) in questo momento. Il tipico lavoro attorno a questo (e quello dimostrato nei buoni documenti MDN per l'API) è quello di impostare un sondaggio e vedere se un gamepad "si presenta" nell'elenco dei dispositivi connessi.

Confondere? Iniziamo con un esempio che supporta solo Firefox:

           

Nell'esempio sopra, iniziamo controllando per vedere se il browser supporta l'API Gamepad. In tal caso, prima aggiorniamo un div con le istruzioni per l'utente, quindi iniziamo ad ascoltare immediatamente entrambi Collegare e disconnect eventi. 

Se esegui questo con Firefox e colleghi il tuo gamepad, dovresti anche premere un pulsante, a quel punto l'evento viene sparato e sei pronto per andare. 

Di nuovo, però, nei miei test, quando ricarico la pagina, il connessione l'evento è immediato. Questo crea un leggero effetto "sfarfallio" che potrebbe essere indecifrabile. Si può effettivamente usare un intervallo per impostare le direzioni per qualcosa come 250 ms dopo che il DOM è stato caricato e solo se nel frattempo non si è verificata una connessione. Ho deciso di mantenere le cose semplici per questo tutorial.

Il nostro codice funziona per Firefox, ma ora aggiungiamo il supporto di Chrome:

           

Il codice è un po 'più complesso ora, ma non così terribilmente. Carica la demo in Chrome e guarda cosa succede.

Nota che abbiamo una nuova variabile globale, hasGP, che useremo come bandiera generale per avere un gamepad connesso. Come prima, abbiamo due listener di eventi, ma ora abbiamo un nuovo intervallo configurato per verificare se esiste un gamepad. Questa è la prima volta che hai visto getGamepads in azione, e lo descriveremo un po 'di più nella prossima sezione, ma per ora sappiamo che restituisce solo un array, e se il primo elemento esiste, possiamo usarlo come un modo per sapere che un gamepad è connesso. 

Usiamo jQuery per attivare lo stesso evento che Firefox avrebbe ricevuto e quindi cancellare l'intervallo. Si noti che questo stesso intervallo verrà attivato una volta anche in Firefox, il che è un po 'dispendioso, ma sinceramente ho pensato che fosse inutile aggiungere ulteriore supporto per sniffare Chrome rispetto a Firefox. Una piccola chiamata come questa sprecata in Firefox non dovrebbe importare affatto.

Ora che abbiamo un gamepad connesso, lavoriamo con esso!

L'oggetto Gamepad

Per darti un'idea di quanti anni ho - ecco il joystick allo stato dell'arte che ho usato per il mio primo sistema di gioco.


Immagine da Wikimedia Commons.

Bello - semplice - e fa male come l'inferno dopo un'ora di gioco. Le console moderne hanno gamepad molto più complessi. Considera il controller PS4:

Immagine da Wikimedia Commons.

Questo controller ha due stick, un pad direzionale, quattro pulsanti principali, altri quattro sul retro, a Condividere e Opzioni pulsante, a PS pulsante, un tocco funky, un altoparlante e una luce. Probabilmente ha anche un condensatore di flusso e un lavello della cucina. 

Fortunatamente, abbiamo accesso a questa bestia tramite l'oggetto Gamepad. Le proprietà includono:

  • id: Questo è il nome del controller. Non aspettarti qualcosa di amichevole da questo. Il mio DualShock 4 è stato segnalato come 54c-5c4-Controller wireless in Firefox, mentre Chrome ha chiamato lo stesso controller Controller wireless (STANDARD GAMEPAD Fornitore: 054c Prodotto: 05c4).
  • indicePoiché l'API Gamepad supporta più controller, questo consente di determinare quale controller numerato è. Potrebbe essere usato per identificare il giocatore uno, due e così via.
  • Mappatura: La mappatura non è qualcosa di cui parleremo qui, ma in sostanza questo è qualcosa che il browser può fare per aiutare a mappare il tuo controller in una configurazione di controller "standard". Se hai giocato a più console, sai che hanno alcune somiglianze in termini di controllo e l'API cerca di "mescolare" il controller in uno standard. Non devi preoccuparti di questo per ora, ma se vuoi maggiori dettagli, controlla la sezione di mappatura dei documenti API.
  • collegato: Un booleano che indica se il controller è ancora connesso.
  • pulsanti: Una matrice di valori dei pulsanti. Ogni pulsante è un'istanza di GamepadButton. Si noti che il GamepadButton oggetto supporta sia una semplice proprietà booleana (pressato) così come a valore proprietà per pulsanti analogici.
  • assi: Una serie di valori che rappresentano i diversi stick sul gamepad. Dato un gamepad con tre stick, avrai una serie di sei elementi, in cui ogni stick è rappresentato da due valori di array. Il primo nella coppia rappresenta X, o il movimento sinistra / destra, mentre il secondo rappresenta Y, movimento su / giù. In tutti i casi il valore sarà compreso tra -1 a 1: per valori sinistra / destra, -1 è lasciato e 1 è giusto; per valori su / giù, -1 è su e 1 è giù. Secondo l'API, la matrice è ordinata secondo "importanza", quindi in teoria è possibile concentrarsi su assi [0] e assi [1] per la maggior parte delle esigenze di gioco. Per rendere le cose più interessanti, usando il mio DualShock 4, Firefox ha riportato tre assi (il che ha senso: vedi l'immagine sopra), ma Chrome ne ha riportati due. Sembra che il d-pad stick sia riportato in Firefox come un asse, ma nessun dato sembra uscirne. In Chrome, il d-pad si presentava come pulsanti aggiuntivi e veniva letto correttamente.
  • timestamp: Infine, questo valore è un timestamp che rappresenta l'ultima volta che l'hardware è stato controllato. In teoria, probabilmente non è qualcosa che useresti.

Ok, quindi è molto da digerire. Nell'esempio seguente, abbiamo semplicemente aggiunto un intervallo per ottenere e ispezionare il primo gamepad e stampare l'ID e quindi i pulsanti e gli assi:

           

Puoi provare la demo in Chrome o Firefox.

Presumo che questo sia abbastanza esplicativo; l'unica vera parte difficile era gestire gli assi. I loop sull'array e conto a due per rappresentare contemporaneamente i valori left / right, up / down. Se apri questo in Firefox e colleghi un DualShock, potresti vedere qualcosa di simile.

Come puoi vedere, il pulsante 2 è stato premuto quando ho scattato il mio screenshot. (Nel caso in cui sei curioso, quello era il X pulsante.) Nota i bastoncini; il mio gamepad era seduto sul mio portatile e quei valori erano costantemente fluttuanti. Non in un modo che implicherebbe che i valori fossero male, di per se-se ho preso il game pad e spinto completamente in una direzione, ho visto il giusto valore. Ma credo che quello che stavo vedendo fosse la sensibilità del controller all'ambiente. O forse gremlin.

Ecco un esempio di come viene visualizzato da Chrome:

Ero, ancora una volta, tenendo premuto il tasto X pulsante, ma nota come l'indice del pulsante è diverso qui. Come puoi dire, avrai bisogno di fare un po 'di ... massaggio se vuoi usare questa API per un gioco. Immagino che potresti controllare entrambi i pulsanti 1 e 2 per "sparare" e seguire una buona quantità di test.

Mettere tutto insieme

Allora, che ne dici di una vera demo? Come la maggior parte dei programmatori che hanno iniziato la loro vita giocando ai videogiochi, ho sognato di diventare un creatore di videogiochi hotshot quando sono cresciuto. Si scopre che la matematica diventa davvero difficile dopo il calcolo e, apparentemente, questa roba "web" ha un futuro, quindi mentre quel futuro non mi ha colpito, mi piacerebbe ancora immaginare che un giorno potrei trasformare questi standard web abilità in un gioco giocabile. Fino a quel giorno, quello che ho oggi è una bella versione a base di tela di Lame. Pong a giocatore singolo Come ho detto, zoppo.

Il gioco rende semplicemente una pagaia e una palla e ti dà il controllo della tastiera sulla palla. Ogni volta che salti la palla, il punteggio sale. Suppongo che abbia senso per il golf piuttosto che per il pong, ma non preoccupiamoci troppo. Il codice può essere trovato in game1.html e puoi giocare alla demo nel tuo browser. 

Non esaminerò tutto il codice qui, ma esaminiamo alcuni frammenti. Innanzitutto, ecco la funzione del ciclo principale che gestisce tutti i dettagli dell'animazione:

function loop () draw.clear (); ball.move (); ball.draw (); paddle.draw (); paddle.move (); draw.text ("Punteggio:" + punteggio, 10, 20, 20); 

La paddle è gestita dalla tastiera utilizzando due semplici gestori di eventi:

$ (finestra) .keydown (function (e) switch (e.keyCode) case 37: input.left = true; break; case 39: input.right = true; break;); $ (finestra) .keyup (function (e) switch (e.keyCode) case 37: input.left = false; break; case 39: input.right = false; break;); 

Il ingresso variabile è una variabile globale che viene rilevata da un oggetto paddle mossa metodo:

this.move = function () if (input.left) this.x - = this.speed; if (this.x < 0) this.x=0;  if(input.right)  this.x += this.speed; if((this.x+this.w) > canvas.width) this.x = canvas.width-this.w;  

Di nuovo, niente di troppo complesso qui. Ecco uno screenshot del gioco in azione. (Lo so, non dovrei lasciare il mio lavoro diurno.)

Quindi, come aggiungiamo il supporto per il gamepad? Fortunatamente, abbiamo già fatto il codice per noi. Nella demo precedente, abbiamo fatto tutto il necessario per controllare e notare gli aggiornamenti del codice. Possiamo prendere quel codice e semplicemente aggiungerlo al codice esistente del gioco. 

Poiché è (praticamente) lo stesso, non lo ripeterò (anche se l'elenco completo è disponibile se lo vuoi), ma condividerò il codice modificato eseguito ogni 100 ms una volta rilevato un gamepad:

function checkGamepad () var gp = navigator.getGamepads () [0]; var axeLF = gp.axes [0]; if (axeLF < -0.5)  input.left = true; input.right = false;  else if(axeLF > 0.5) input.left = false; input.right = true;  else input.left = false; input.right = false;  

Di nuovo, puoi provare la demo in entrambi i browser.

Come con l'esempio precedente, abbiamo assunto che ci interessa solo un gamepad. Dato che il nostro gioco ha solo una pagaia e si muove solo orizzontalmente, possiamo cavarcela controllando solo il primo asse. Ricorda, secondo l'API questo dovrebbe essere il "più importante", e nei miei test è stata la levetta sinistra, che è abbastanza standard per i giochi. 

Dal momento che il nostro gioco utilizza una variabile globale, ingresso, per rappresentare il movimento sinistro e destro, tutto ciò che devo fare è modificare quel valore in base al valore dell'asse. Ora, nota che non ho semplicemente controllato "meno di zero" e "maggiore di zero". Perché? Se ti ricordi della demo precedente, il gamepad era molto sensibile e spesso riportava i valori anche quando non pensavo di aver effettivamente spostato la levetta. Utilizzando un valore limite di .5 conferisce al controllo un po 'più di stabilità. (E ovviamente questo è il tipo di cosa che dovresti modificare per vedere cosa "sente" giusto.) 

Tutto sommato, ho aggiunto all'incirca 25 linee di codice al mio gioco per aggiungere supporto al gamepad. Che rocce.

Inizio partita!

Spero che tu l'abbia visto, mentre ci sono sicuramente alcune idiosincrasie, l'API di Gamepad ora ha il supporto in due browser principali, ed è qualcosa che penso che gli sviluppatori dovrebbero davvero iniziare a prendere in considerazione per i loro giochi.

risorse

Ecco alcune risorse aggiuntive per aiutarti a saperne di più sull'API del gamepad.

  • Utilizzo dell'API del gamepad
  • Specifiche del gamepad
  • Gamepad.js - Una libreria Javascript per abilitare l'uso di gamepad e joystick nel browser.
  • Controlli del gamepad per giochi HTML5
  • La versione di Wii U (totalmente diversa dalle specifiche - buon lavoro, Nintendo!)

Riferimenti

  • Preview image credit: Controller per videogiochi progettato da Uriel Sosa del progetto Noun