Utilisation de l'API HTML5 Gamepad pour ajouter la prise en charge du contrôleur aux jeux par navigateur

Le jeu sur Internet devenant de plus en plus populaire, le contrôle des entrées est l’un des principaux problèmes des joueurs. Alors que mes premiers jeux FPS étaient uniquement basés sur la souris et le clavier, je suis maintenant tellement plus habitué à utiliser un bon contrôleur de console que je préfère l'utiliser pour tout, y compris les jeux Web.. 

Heureusement, l'API HTML5 Gamepad existe pour permettre aux développeurs Web d'accéder par programmation aux contrôleurs de jeu. Malheureusement, bien que cette API existe depuis longtemps, elle n’est que maintenant, lentement, en train d’entrer dans les versions les plus récentes des navigateurs de bureau. Il a longtemps traîné dans une version de Firefox (pas une version supérieure, personne ne chaque nuit construire) et était problématique dans Chrome. Maintenant, il est-bien-pas parfait, mais légèrement moins problématique et plutôt facile à utiliser. 

Dans cet article, je vais aborder les différentes fonctionnalités de l'API, comment le faire fonctionner à la fois dans Firefox et Chrome, et montrer un vrai jeu (bien que simple) et à quel point il est facile d'y ajouter un support de manette de jeu..

Les bases

L'API Gamepad comprend les fonctionnalités suivantes:

  • La capacité d'écouter relier et déconnecter événements.
  • La capacité de reconnaître plusieurs manettes de jeu. (En théorie, vous pouvez brancher autant de manettes de jeu que de ports USB.)
  • La possibilité d'inspecter ces manettes de jeu et de reconnaître leur nombre d'axes (manettes de jeu), leur nombre de boutons (avez-vous déjà joué à une console de jeu moderne?) Et dans quel état se trouvent chacun de ces éléments.

Commençons par discuter de la façon dont vous pouvez détecter le support d’un gamepad à un niveau élevé.. 

Firefox et Chrome prennent en charge une méthode sur navigateur, getGamepads (), qui renvoie un tableau de tous les périphériques de manette de jeu connectés. Nous pouvons l'utiliser comme méthode simple pour détecter si l'API Gamepad est présente. Voici une fonction simple pour cette vérification:

function canGame () return "getGamepads" dans le navigateur; 

Jusqu'ici tout va bien. Maintenant pour la partie funky. L'API de la manette de jeu prend en charge les événements détectant la connexion et la déconnexion d'une manette de jeu. Mais que se passe-t-il si l'utilisateur dispose déjà d'une manette de jeu connectée à son ordinateur portable lorsqu'il frappe votre page? Normalement, la page Web attend que l'utilisateur fasse quelque chose, vraiment, avec le gamepad. Cela signifie que nous devons fournir à l'utilisateur un type de message lui indiquant qu'il doit "activer" le support pour la manette de jeu si elle est connectée. Vous pouvez leur dire d'appuyer sur n'importe quel bouton ou de déplacer un bâton. 

Pour rendre les choses encore plus intéressantes, cette vérification particulière ne semble pas nécessaire lorsque vous rechargez la page. Vous constaterez qu'une fois que vous avez utilisé l'API Gamepad sur une page, puis que vous l'avez rechargée, la page reconnaît ce fait et considère automatiquement qu'elle est connectée..

Mais attendez, il ya mieux. Chrome ne prend pas en charge les événements connectés (ou déconnectés) pour le moment. La solution typique pour cela (et celle présentée dans les bonnes documentations MDN pour l'API) est de configurer un sondage et de voir si un gamepad "apparaît" dans la liste des périphériques connectés..

Déroutant? Commençons par un exemple ne prenant en charge que Firefox:

           

Dans l'exemple ci-dessus, nous commençons par vérifier si le navigateur prend en charge l'API Gamepad. Si tel est le cas, nous mettons d'abord à jour une div avec des instructions pour l'utilisateur, puis commençons à écouter immédiatement les deux. relier et déconnecter événements. 

Si vous lancez ceci avec Firefox et connectez votre manette de jeu, vous devriez alors aussi appuyer sur un bouton. L'événement est alors déclenché et vous êtes prêt.. 

Encore une fois, cependant, lors de mes tests, lorsque je recharge la page, le lien l'événement est immédiat. Cela crée un léger "scintillement" qui peut être indésirable. Vous pouvez en fait utiliser un intervalle pour définir les instructions pour quelque chose comme 250 ms après le chargement du DOM et ne l'inviter que si une connexion ne s'est pas établie entre-temps. J'ai décidé de garder les choses simples pour ce tutoriel.

Notre code fonctionne pour Firefox, mais ajoutons maintenant le support de Chrome:

           

Le code est un peu plus complexe maintenant, mais pas tellement. Chargez la démo dans Chrome et voyez ce qui se passe.

Notez que nous avons une nouvelle variable globale, hasGP, que nous utiliserons comme un drapeau général pour avoir un gamepad connecté. Comme auparavant, nous avons deux écouteurs d'événement, mais nous avons maintenant un nouvel intervalle configuré pour vérifier si une manette de jeu existe. C'est la première fois que tu vois obtenir des gamepads en action, et nous le décrirons un peu plus dans la section suivante, mais pour le moment sachez qu'il renvoie simplement un tableau, et si le premier élément existe, nous pouvons l'utiliser comme moyen de savoir qu'un manette de jeu est connectée. 

Nous utilisons jQuery pour déclencher le même événement que Firefox aurait reçu, puis effacer l'intervalle. Notez que ce même intervalle se déclenchera également une fois dans Firefox, ce qui est légèrement inutile, mais honnêtement, j’ai pensé que c’était une perte de temps d’ajouter un support supplémentaire pour renifler Chrome par rapport à Firefox. Un petit appel comme celui gaspillé dans Firefox ne devrait pas avoir d'importance du tout.

Maintenant que nous avons un gamepad connecté, travaillons avec!

L'objet Gamepad

Pour vous donner une idée de mon âge - voici le joystick à la pointe de la technologie que j'ai utilisé pour mon premier système de jeu.


Image de Wikimedia Commons.

Nice - simple - et ça fait terriblement mal après une heure de jeu. Les consoles modernes ont des gamepads beaucoup plus complexes. Considérez le contrôleur PS4:

Image de Wikimedia Commons.

Ce contrôleur a deux manettes, un pavé directionnel, quatre boutons principaux, quatre autres à l’arrière, un Partager et Les options bouton, un PS bouton, quelque chose de contrôle tactile génial, un haut-parleur et une lumière. Il a aussi probablement un condensateur de flux et un évier de cuisine. 

Heureusement, nous avons accès à cette bête via l'objet Gamepad. Les propriétés comprennent:

  • identifiant: Ceci est le nom du contrôleur. Ne vous attendez pas à quelque chose d'amical de cela. Mon DualShock 4 a été signalé comme 54c-5c4-contrôleur sans fil dans Firefox, alors que Chrome a appelé le même contrôleur Contrôleur sans fil (STANDARD GAMEPAD Fournisseur: 054c Produit: 05c4).
  • indice: Puisque l’API Gamepad prend en charge plusieurs contrôleurs, celui-ci vous permet de déterminer le type de contrôleur numéroté. Il pourrait être utilisé pour identifier le joueur un, deux, etc..
  • cartographie: La cartographie n’est pas une question que nous allons couvrir ici, mais c’est essentiellement une chose que le navigateur peut faire pour aider à mapper votre contrôleur particulier vers une configuration de contrôleur "standard". Si vous avez utilisé plusieurs consoles, vous savez qu'elles présentent des similitudes en termes de contrôle, et l'API tente de "mash" votre contrôleur dans un standard. Vous n'avez pas à vous soucier de cela pour l'instant, mais si vous souhaitez plus de détails, consultez la section de mappage des documents de l'API..
  • connecté: Un booléen indiquant si le contrôleur est toujours connecté.
  • boutons: Un tableau de valeurs de bouton. Chaque bouton est une instance de GamepadButton. Notez que le GamepadButton objet supporte à la fois une simple propriété booléenne (pressé) ainsi qu'une valeur propriété pour les boutons analogiques.
  • axes: Un tableau de valeurs représentant les différents sticks du gamepad. Avec un gamepad avec trois sticks, vous aurez un tableau de six éléments, chaque stick étant représenté par deux valeurs de tableau. Le premier de la paire représente le mouvement X, ou gauche / droite, tandis que le second représente le mouvement Y, haut / bas. Dans tous les cas, la valeur sera comprise entre -1 à 1: pour les valeurs gauche / droite, -1 est laissé et 1 est juste; pour les valeurs haut / bas, -1 est en place et 1 est éteint. Selon l’API, le tableau est trié par «importance». En théorie, vous pouvez donc vous concentrer sur axes [0] et axes [1] pour la plupart des besoins de jeu. Pour rendre les choses plus intéressantes, en utilisant mon DualShock 4, Firefox a signalé trois axes (ce qui est logique - voir l'image ci-dessus), mais Chrome en a signalé deux. Il semble que le stick d-pad soit signalé dans Firefox comme un axe, mais aucune donnée ne semble en sortir. Dans Chrome, le d-pad apparaissait comme des boutons supplémentaires et était correctement lu..
  • horodatage: Enfin, cette valeur est un horodatage représentant la dernière vérification du matériel. En théorie, ce n’est probablement pas quelque chose que vous utiliseriez.

Ok, donc c'est beaucoup à digérer. Dans l'exemple ci-dessous, nous avons simplement ajouté un intervalle pour extraire et inspecter le premier gamepad, puis imprimer l'ID, puis les boutons et les axes:

           

Vous pouvez essayer la démo dans Chrome ou Firefox.

Je suppose que tout cela est assez explicite; le seul véritable problème était de manipuler les axes. Je boucle sur le tableau et compte par deux pour représenter les deux valeurs gauche / droite, haut / bas à la fois. Si vous ouvrez ceci dans Firefox et connectez un DualShock, vous pouvez voir quelque chose comme ceci.

Comme vous pouvez le constater, vous avez appuyé sur le bouton 2 lorsque j'ai pris ma capture d'écran. (Au cas où vous seriez curieux, c'était le X bouton.) Notez les bâtons; mon gamepad était assis sur mon ordinateur portable et ces valeurs fluctuaient constamment. Pas d'une manière qui impliquerait que les valeurs étaient mal, En soi, si je prenais la manette de jeu et que je poussais à fond dans une direction, je voyais la bonne valeur. Mais je crois que ce que je voyais était à quel point le contrôleur était sensible à l'environnement. Ou peut-être des gremlins.

Voici un exemple montrant comment Google Chrome l'affiche:

J'étais, encore, tenant le X bouton-mais remarquez comment l'index du bouton est différent ici. Comme vous pouvez le constater, vous devrez faire un peu de… massage si vous souhaitez utiliser cette API pour un jeu. J'imagine que vous pouvez vérifier le "feu" des deux boutons 1 et 2, puis effectuer de nombreux tests..

Mettre tous ensemble

Alors, que diriez-vous d'une vraie démo? Comme la plupart des programmeurs qui ont commencé leur vie à jouer à des jeux vidéo, je rêvais d’être un créateur de jeux vidéo très apprécié lorsque je serais grand. Il s'avère que les mathématiques deviennent très difficiles après le calcul, et apparemment ce matériau "Web" a un avenir, alors même si cet avenir ne s'est pas bien passé pour moi, j'aimerais quand même imaginer qu'un jour je pourrais transformer ces standards Web compétences dans un jeu jouable. Jusqu’à ce jour, ce que j’ai aujourd’hui est une version boiteuse de pong basée sur une toile. Pong solo. Comme je l'ai dit, boiteux.

Le jeu restitue simplement une palette et une balle, et vous permet de contrôler le ballon au clavier. Chaque fois que vous ratez le ballon, le score augmente. Ce qui a du sens pour le golf plutôt que le pong, je suppose, mais ne nous inquiétons pas trop à ce sujet. Le code peut être trouvé dans game1.html et vous pouvez jouer la démo dans votre navigateur. 

Je ne vais pas passer en revue tout le code ici, mais regardons quelques extraits. Tout d'abord, voici la fonction de boucle principale qui gère tous les détails de l'animation:

fonction loop () draw.clear (); ball.move (); ball.draw (); paddle.draw (); paddle.move (); draw.text ("Score:" + score, 10, 20, 20); 

La palette est pilotée par le clavier à l'aide de deux gestionnaires d'événements simples:

$ (fenêtre) .keydown (fonction (e) commutateur (e.keyCode) cas 37: input.left = true; break; cas 39: input.right = true; break;); $ (fenêtre) .keyup (fonction (e) commutateur (e.keyCode) cas 37: input.left = false; break; cas 39: input.right = false; break;); 

le contribution variable est une variable globale qui est captée par un objet de palette bouge toi méthode:

this.move = function () if (input.left) this.x - = this.speed; si (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;  

Encore une fois, rien de trop complexe ici. Voici une capture d'écran du jeu en action. (Je sais, je ne devrais pas quitter mon emploi.)

Alors, comment pouvons-nous ajouter le support du gamepad? Heureusement, le code est déjà fait pour nous. Dans la démo précédente, nous avons fait tout ce qui était nécessaire pour vérifier et noter les mises à jour du code. Nous pouvons prendre ce code et l'ajouter simplement au code existant du jeu. 

Comme il est (pratiquement) identique, je ne le répéterai pas (bien que la liste complète soit disponible si vous le souhaitez), mais je partagerai le code modifié exécuté toutes les 100 ms une fois la manette détectée:

fonction checkGamepad () var gp = navigator.getGamepads () [0]; var axeLF = gp.axes [0]; si (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;  

Encore une fois, vous pouvez essayer la démo dans les deux navigateurs.

Comme dans l'exemple précédent, nous avons supposé que nous ne nous préoccupions que d'un seul gamepad. Comme notre jeu n’a qu’une palette et qu’il ne se déplace que horizontalement, nous pouvons nous en tirer en ne vérifiant que le tout premier axe. Rappelez-vous que, selon l'API, il devrait s'agir du "plus important", et lors de mes tests, il s'agissait du stick gauche, qui est plutôt standard pour les jeux.. 

Puisque notre jeu utilise une variable globale, contribution, pour représenter les mouvements gauche et droit, tout ce que j'ai à faire est de modifier cette valeur en fonction de la valeur de l'axe. Maintenant, remarquez que je n'ai pas simplement vérifié "moins que zéro" et "plus grand que zéro". Pourquoi? Si vous vous souvenez de la démo précédente, la manette de jeu était très sensible et rapportait souvent des valeurs même lorsque je ne pensais pas avoir réellement déplacé le manche. En utilisant une valeur limite de .5 donne au contrôle un peu plus de stabilité. (Et évidemment, c’est le genre de chose que vous auriez besoin de peaufiner pour voir ce qui "se sent" bien.) 

En tout et pour tout, j'ai ajouté environ 25 lignes de code à mon jeu pour ajouter le support du gamepad. Ça déchire.

Jeu sur!

J'espère que vous avez vu que, bien qu'il existe certaines idiosyncrasies, l'API Gamepad est désormais prise en charge par deux principaux navigateurs, et je pense que c'est quelque chose que les développeurs devraient vraiment commencer à envisager pour leurs jeux..

Ressources

Voici quelques ressources supplémentaires pour vous aider à en apprendre davantage sur l'API Gamepad..

  • Utilisation de l'API Gamepad
  • Spécifications de la manette de jeu
  • Gamepad.js - Une bibliothèque Javascript pour permettre l'utilisation de manettes de jeu et de manettes de jeu dans le navigateur..
  • Commandes de la manette de jeu pour les jeux HTML5
  • Version Wii U (totalement différente de la spécification - bon travail, Nintendo!)

Références

  • Preview image credit: Contrôleur de jeu vidéo conçu par Uriel Sosa du projet Noun