Verwenden der HTML5-Gamepad-API zum Hinzufügen von Controller-Unterstützung zu Browserspielen

Da webbasiertes Spielen immer beliebter wird, ist die Eingabekontrolle einer der größten Punkte für Spieler. Während meine ersten FPS-Spiele rein maus- und tastaturbasiert waren, habe ich mich inzwischen an einen richtigen Konsolencontroller so gewöhnt, dass ich ihn eher für alles verwenden würde, auch für webbasierte Spiele. 

Glücklicherweise gibt es die HTML5-Gamepad-API, mit der Webentwickler programmgesteuert auf Gamecontroller zugreifen können. Unglücklicherweise ist diese API zwar schon lange auf dem Markt, aber erst jetzt, langsam in die neuesten Versionen von Desktop-Browsern. Es wurde lange Zeit in einem Build von Firefox geschmolzen (kein höherer Build, keiner) nächtlich bauen) und war in Chrome problematisch. Nun, es ist nicht perfekt, aber etwas weniger problematisch und eigentlich ziemlich einfach zu bedienen. 

In diesem Artikel werde ich die verschiedenen Funktionen der API besprechen, wie sie in Firefox und Chrome zum Laufen gebracht werden können, ein reales (wenn auch einfaches) Spiel zeigen und wie einfach es ist, Gamepad-Unterstützung hinzuzufügen.

Die Grundlagen

Die Gamepad-API umfasst die folgenden Funktionen:

  • Die Fähigkeit zu hören verbinden und trennen Veranstaltungen.
  • Die Fähigkeit, mehrere Gamepads zu erkennen. (Theoretisch könnten Sie so viele Gamepads wie USB-Anschlüsse anschließen.)
  • Die Möglichkeit, diese Gamepads zu inspizieren und zu erkennen, wie viele Achsen sie haben (Joysticks), wie viele Tasten sie haben (haben Sie in letzter Zeit eine moderne Spielkonsole gespielt?) Und in welchem ​​Zustand sich diese einzelnen Elemente befinden.

Beginnen wir mit der Diskussion, wie Sie die Unterstützung für ein Gamepad auf hohem Niveau erkennen können. 

Sowohl Firefox als auch Chrome unterstützen eine Methode Navigator, getGamepads (), Dadurch wird ein Array aller angeschlossenen Gamepad-Geräte zurückgegeben. Wir können dies als einfache Methode verwenden, um festzustellen, ob die Gamepad-API vorhanden ist. Hier ist eine einfache Funktion für diese Überprüfung:

function canGame () gibt "getGamepads" im Navigator zurück; 

So weit, ist es gut. Nun zum funky Teil. Die Gamepad-API unterstützt Ereignisse, die erkennen, wann ein Gamepad verbunden und getrennt wird. Aber was passiert, wenn der Benutzer bereits ein Gamepad an seinen Laptop angeschlossen hat, wenn er auf Ihre Seite trifft? Normalerweise wartet die Webseite darauf, dass der Benutzer mit dem eigentlichen Gamepad etwas unternimmt. Dies bedeutet, dass wir dem Benutzer eine Art Nachricht übermitteln müssen, die ihn informiert, dass er die Unterstützung für das Gamepad "aufwecken" muss, wenn es angeschlossen ist. Sie können ihnen sagen, dass sie eine beliebige Taste drücken oder einen Stick bewegen sollen. 

Um die Dinge noch interessanter zu machen, scheint diese spezielle Prüfung beim Neuladen der Seite nicht erforderlich zu sein. Sobald Sie die Gamepad-API auf einer Seite verwendet und anschließend neu geladen haben, erkennt die Seite diese Tatsache und betrachtet sie automatisch als verbunden.

Aber warten, es wird besser. Chrome unterstützt derzeit keine verbundenen (oder getrennten) Ereignisse. In der Regel (und in den guten MDN-Dokumenten für die API gezeigt) können Sie eine Umfrage einrichten und feststellen, ob ein Gamepad in der Liste der verbundenen Geräte angezeigt wird.

Verwirrend? Beginnen wir mit einem Beispiel, das nur Firefox unterstützt:

           

Im obigen Beispiel prüfen wir zunächst, ob der Browser die Gamepad-API unterstützt. Wenn dies der Fall ist, aktualisieren wir zunächst ein div mit Anweisungen für den Benutzer und hören dann sofort auf beide verbinden und trennen Veranstaltungen. 

Wenn Sie dies mit Firefox ausführen und Ihr Gamepad anschließen, sollten Sie auch eine Schaltfläche drücken. Dann wird das Ereignis ausgelöst und Sie können loslegen. 

Wenn ich jedoch die Seite neu lade, wird in meinen Tests die Verbindung Ereignis ist sofort. Dies bewirkt einen leichten "Flicker" -Effekt, der möglicherweise nicht störend ist. Sie können tatsächlich ein Intervall verwenden, um die Richtungen für etwa 250 ms festzulegen, nachdem das DOM geladen wurde, und nur aufzufordern, wenn in der Zwischenzeit keine Verbindung hergestellt wurde. Ich beschloss, die Dinge für dieses Tutorial einfach zu halten.

Unser Code funktioniert für Firefox, aber jetzt fügen wir Chrome-Unterstützung hinzu:

           

Der Code ist jetzt etwas komplexer, aber nicht so schlimm. Laden Sie die Demo in Chrome und sehen Sie, was passiert.

Beachten Sie, dass wir eine neue globale Variable haben, hasGP, dass wir als allgemeine Flagge für die Verbindung eines Gamepads verwenden. Wie zuvor haben wir zwei Ereignis-Listener, aber jetzt haben wir ein neues Intervall eingerichtet, um zu prüfen, ob ein Gamepad vorhanden ist. Dies ist das erste Mal, dass du gesehen hast getGamepads In Aktion, und wir werden es im nächsten Abschnitt etwas näher beschreiben, aber wissen Sie jetzt, dass nur ein Array zurückgegeben wird. Wenn das erste Element vorhanden ist, können Sie dies als Möglichkeit nutzen, um zu wissen, dass ein Gamepad angeschlossen ist. 

Wir verwenden jQuery, um dasselbe Ereignis auszulösen, das Firefox erhalten hätte, und dann das Intervall zu löschen. Beachten Sie, dass das gleiche Intervall auch einmal in Firefox ausgelöst wird, was etwas verschwenderisch ist, aber ehrlich gesagt, dachte ich, es wäre Zeitverschwendung, zusätzliche Unterstützung für Chrome und Firefox zu verwenden. Ein kleiner Anruf wie dieser in Firefox verschwendete Anruf sollte überhaupt keine Rolle spielen.

Nun, da wir ein angeschlossenes Gamepad haben, arbeiten wir damit!

Das Gamepad-Objekt

Um Ihnen eine Vorstellung davon zu geben, wie alt ich bin - hier ist der hochmoderne Joystick, den ich für mein erstes Spielesystem verwendet habe.


Bild aus Wikimedia Commons.

Schön - einfach - und es tat nach einer Stunde verdammt weh. Moderne Konsolen haben viel komplexere Gamepads. Betrachten Sie den PS4-Controller:

Bild aus Wikimedia Commons.

Dieser Controller verfügt über zwei Steuerknüppel, ein Richtungspad, vier Hauptknöpfe, vier weitere auf der Rückseite, a Aktie und Optionen Taste, a PS Taste, etwas funky Touch Control Ding, ein Lautsprecher und ein Licht. Es hat wahrscheinlich auch einen Flussmittelkondensator und eine Küchenspüle. 

Glücklicherweise haben wir über das Gamepad-Objekt Zugriff auf diese Bestie. Eigenschaften umfassen:

  • Ich würde: Dies ist der Name des Controllers. Erwarten Sie nicht etwas Freundliches. Mein DualShock 4 wurde als gemeldet 54c-5c4-Wireless Controller in Firefox, während Chrome den gleichen Controller bezeichnet Wireless Controller (STANDARD GAMEPAD Hersteller: 054c Produkt: 05c4).
  • Index: Da die Gamepad-API mehrere Controller unterstützt, können Sie mit diesem Controller ermitteln, um welchen Controller es sich handelt. Es kann verwendet werden, um Spieler eins, zwei usw. zu identifizieren.
  • Kartierung: Mapping ist nicht etwas, das wir hier behandeln werden, aber im Wesentlichen kann der Browser dazu beitragen, Ihren speziellen Controller einem "Standard" -Controller-Setup zuzuordnen. Wenn Sie mehrere Konsolen gespielt haben, wissen Sie, dass sie hinsichtlich der Steuerung einige Ähnlichkeiten aufweisen, und die API versucht, Ihren Controller in einen Standard zu mischen. Sie müssen sich im Moment nicht darum kümmern, aber wenn Sie mehr Details wünschen, überprüfen Sie den Zuordnungsabschnitt der API-Dokumente.
  • in Verbindung gebracht: Ein boolescher Wert, der angibt, ob der Controller noch angeschlossen ist.
  • Tasten: Ein Array von Schaltflächenwerten. Jede Schaltfläche ist eine Instanz von GamepadButton. Notiere dass der GamepadButton object unterstützt sowohl eine einfache boolesche Eigenschaft (gedrückt) sowie a Wert Eigenschaft für analoge Tasten.
  • Achsen: Eine Reihe von Werten, die die verschiedenen Stöcke auf dem Gamepad darstellen. Bei einem Gamepad mit drei Stöcken erhalten Sie ein Array mit sechs Elementen, wobei jeder Stick durch zwei Array-Werte dargestellt wird. Der erste Teil des Paares steht für X- oder Links- / Rechtsbewegung, während der zweite für Y-Bewegung nach oben / unten steht. In allen Fällen reicht der Wert von -1 zu 1: für linke / rechte Werte, -1 ist übrig und 1 ist richtig; für Auf / Ab-Werte, -1 ist auf und 1 ist unten. Gemäß der API ist das Array nach "Wichtigkeit" sortiert, sodass Sie sich theoretisch darauf konzentrieren können Achsen [0] und Achsen [1] für die meisten Gaming-Bedürfnisse. Um die Sache noch interessanter zu machen, meldete Firefox mit meinem DualShock 4 drei Achsen (was sinnvoll ist, siehe Abbildung oben), Chrome jedoch zwei. Es scheint, als würde der D-Pad-Stick in Firefox als Achse gemeldet, aber es scheinen keine Daten herauszukommen. In Chrome wurde das D-Pad als zusätzliche Schaltflächen angezeigt und richtig gelesen.
  • Zeitstempel: Schließlich ist dieser Wert ein Zeitstempel, der die letzte Überprüfung der Hardware angibt. Theoretisch ist dies wahrscheinlich nichts, was Sie verwenden würden.

Okay, das ist viel zu verdauen. Im folgenden Beispiel haben wir einfach ein Intervall hinzugefügt, um das erste Gamepad abzurufen und zu prüfen, die ID und dann die Schaltflächen und Achsen auszudrucken:

           

Sie können die Demo entweder in Chrome oder Firefox testen.

Ich gehe davon aus, dass dies alles ziemlich selbsterklärend ist. Der einzige wirklich schwierige Teil war der Umgang mit den Achsen. Ich schleife über das Array und zähle um zwei, um sowohl die linken / rechten als auch die auf / ab-Werte auf einmal darzustellen. Wenn Sie dies in Firefox öffnen und einen DualShock anschließen, sehen Sie möglicherweise so etwas.

Wie Sie sehen, wurde Button 2 gedrückt, als ich meinen Screenshot machte. (Falls Sie neugierig sind, das war das X Taste.) Beachten Sie die Sticks; Mein Gamepad saß auf meinem Laptop und diese Werte schwankten ständig. Nicht in einer Weise, die die Werte implizieren würde Schlecht, per se - wenn ich den Gamepad aufhob und ganz in eine Richtung drückte, sah ich den richtigen Wert. Aber ich glaube, ich habe gesehen, wie empfindlich der Controller für die Umgebung ist. Oder vielleicht Gremlins.

Hier ein Beispiel, wie Chrome es anzeigt:

Ich hielt wieder die X Button-aber beachten Sie, wie der Button-Index hier anders ist. Wie Sie sehen können, müssen Sie ein wenig… massieren, wenn Sie diese API für ein Spiel verwenden möchten. Ich könnte mir vorstellen, dass Sie beide Buttons 1 und 2 auf "Feuer" überprüfen und eine Reihe von Tests durchführen können.

Alles zusammenfügen

Wie wäre es mit einer echten Demo? Wie die meisten Programmierer, die ihr Leben mit Videospielen angefangen haben, träumte ich davon, in meiner Jugend ein heißer Spieler von Videospielen zu sein. Es stellt sich heraus, dass die Mathematik nach dem Kalkül wirklich hart wird, und anscheinend hat dieses "Web" -Ding eine Zukunft, und obwohl diese Zukunft für mich nicht ausfiel, würde ich mir immer noch gerne vorstellen, dass ich eines Tages diese Webstandards ändern könnte Fähigkeiten in ein spielbares Spiel. Bis zu diesem Tag habe ich heute eine ziemlich lahmenhafte Version von Pong auf Leinwand. Einzelspieler-Pong Wie gesagt, lahm.

Das Spiel rendert einfach ein Paddel und einen Ball und gibt der Tastatur die Kontrolle über den Ball. Jedes Mal, wenn Sie den Ball verpassen, steigt die Punktzahl. Was für Golf eher Sinn macht als Pong, nehme ich an, aber machen wir uns nicht allzu viele Sorgen. Den Code finden Sie in game1.html und Sie können die Demo in Ihrem Browser abspielen. 

Ich werde hier nicht den gesamten Code durchgehen, aber schauen wir uns ein paar Ausschnitte an. Zunächst die Hauptschleifenfunktion, die alle Animationsdetails behandelt:

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

Das Paddel wird von der Tastatur mit zwei einfachen Ereignishandlern gesteuert:

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

Das Eingang Variable ist eine globale Variable, die von einem Paddle-Objekt erfasst wird Bewegung Methode:

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;  

Wieder nichts zu komplexes hier. Hier ist ein Screenshot des Spiels in Aktion. (Ich weiß, ich sollte meinen Tagesjob nicht aufgeben.)

Wie fügen wir Gamepad-Unterstützung hinzu? Glücklicherweise haben wir den Code bereits für uns erstellt. In der vorherigen Demo haben wir alles getan, um nach Updates des Codes zu suchen und diese zu bemerken. Wir können diesen Code nehmen und ihn einfach an den vorhandenen Code des Spiels anhängen. 

Da es (praktisch) derselbe ist, werde ich es nicht wiederholen (obwohl die vollständige Auflistung verfügbar ist, wenn Sie es wollen), aber ich werde den modifizierten Code alle 100 ms freigeben, sobald ein Gamepad erkannt wird:

Funktion 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 = falsch;  

Sie können die Demo erneut in beiden Browsern testen.

Wie im vorherigen Beispiel haben wir angenommen, dass uns nur ein Gamepad wichtig ist. Da unser Spiel nur ein Paddel hat und sich nur horizontal bewegt, können wir nur die erste Achse überprüfen. Denken Sie daran, dass dies laut API die "wichtigste" sein sollte, und in meinen Tests war es der linke Stick, der für Spiele ziemlich Standard ist. 

Da unser Spiel eine globale Variable verwendet, Eingang, Um die Bewegung nach links und rechts darzustellen, muss ich nur diesen Wert basierend auf dem Achsenwert ändern. Beachten Sie, dass ich nicht einfach nach "weniger als null" und "größer als null" gesucht habe. Warum? Wenn Sie sich an die frühere Demo erinnern, war das Gamepad sehr empfindlich und meldete häufig Werte, selbst wenn ich nicht dachte, ich hätte den Stick tatsächlich bewegt. Verwenden Sie einen Grenzwert von .5 gibt der Steuerung ein bisschen mehr Stabilität. (Und natürlich ist es die Art von Dingen, die Sie anpassen müssen, um zu sehen, was sich richtig anfühlt.) 

Alles in allem habe ich meinem Spiel etwa 25 Zeilen Code hinzugefügt, um die Unterstützung für Gamepads hinzuzufügen. Das rockt.

Spiel weiter!

Hoffentlich haben Sie gesehen, dass die Gamepad-API jetzt zwar in einigen großen Browsern Unterstützung bietet, aber es gibt definitiv einige Eigenheiten, und ich denke, dass Entwickler dies für ihre Spiele wirklich in Betracht ziehen sollten.

Ressourcen

Hier finden Sie einige zusätzliche Ressourcen, um mehr über die Gamepad-API zu erfahren.

  • Verwenden der Gamepad-API
  • Gamepad-Spezifikation
  • Gamepad.js - Eine Javascript-Bibliothek, die die Verwendung von Gamepads und Joysticks im Browser ermöglicht.
  • Gamepad-Steuerelemente für HTML5-Spiele
  • Wii U's Version (völlig anders als die Spezifikation - gute Arbeit, Nintendo!)

Verweise

  • Vorschaubild: Video Game Controller von Uriel Sosa aus dem Noun-Projekt