Zeigersperre und Ego-Shooter-Steuerung

McCutchan
John McCutchan

Einleitung

Die Pointer Lock API hilft bei der ordnungsgemäßen Implementierung der Ego-Shooter-Steuerelemente in einem Browserspiel. Ohne relative Mausbewegung könnte der Cursor des Spielers beispielsweise den rechten Rand des Bildschirms treffen und weitere Bewegungen nach rechts würden nicht gelenkt. Die Ansicht würde nicht weiter nach rechts schwenken und der Spieler könnte die Bösewichte nicht verfolgen und sie mit seinem Maschinengewehr bedrängen. Der Spieler wird zerbrochen und frustriert. Mit Zeigersperre ist dieses suboptimale Verhalten nicht möglich.

Mit der Pointer Lock API kann Ihre Anwendung Folgendes tun:

  • Zugriff auf die Rohdaten der Maus, einschließlich der relativen Mausbewegungen
  • Alle Mausereignisse an ein bestimmtes Element weiterleiten

Als Nebeneffekt beim Aktivieren der Zeigersperre wird der Mauszeiger ausgeblendet, sodass Sie bei Bedarf einen anwendungsspezifischen Zeiger zeichnen oder ihn ausgeblendet lassen können, sodass der Nutzer den Frame mit der Maus verschieben kann. Die relative Mausbewegung ist das Delta der Mauszeigerposition im Vergleich zum vorherigen Frame, unabhängig von der absoluten Position. Bewegt sich der Mauszeiger beispielsweise von (640, 480) auf (520, 490), betrug die relative Bewegung (-120, 10). Unten sehen Sie ein interaktives Beispiel, das die Rohdaten der Mauspositionsdeltas zeigt.

Dieses Tutorial behandelt zwei Themen: die praktischen Funktionen zum Aktivieren und Verarbeiten von Zeigersperr-Ereignissen und die Implementierung des Ego-Shooter-Steuerschemas. Richtig. Wenn Sie diesen Artikel gelesen haben, wissen Sie, wie Sie die Zeigersperre verwenden und Steuerelemente im Quake-Stil für Ihr eigenes Browserspiel implementieren.

Browserkompatibilität

Unterstützte Browser

  • 37
  • 13
  • 50
  • 10.1

Quelle

Zeigersperre

Funktionserkennung

Um festzustellen, ob der Browser des Nutzers die Zeigersperre unterstützt, müssen Sie im Dokumentobjekt nach pointerLockElement oder einer Version mit dem Anbieter-Präfix suchen. Im Code:

var havePointerLock = 'pointerLockElement' in document ||
    'mozPointerLockElement' in document ||
    'webkitPointerLockElement' in document;

Die Zeigersperre ist derzeit nur in Firefox und Chrome verfügbar. Opera und IE unterstützen diese Funktion noch nicht.

Wird aktiviert

Das Aktivieren der Zeigersperre erfolgt in zwei Schritten. Zuerst fordert Ihre Anwendung die Aktivierung der Zeigersperre für ein bestimmtes Element an. Unmittelbar nachdem der Nutzer die Berechtigung erteilt hat, wird ein pointerlockchange-Ereignis ausgelöst. Der Nutzer kann die Zeigersperre jederzeit durch Drücken der Esc-Taste aufheben. Ihre Anwendung kann die Zeigersperre auch progrmamatisch beenden. Wenn die Zeigersperre abgebrochen wird, wird ein pointerlockchange-Ereignis ausgelöst.

element.requestPointerLock = element.requestPointerLock ||
                 element.mozRequestPointerLock ||
                 element.webkitRequestPointerLock;
// Ask the browser to lock the pointer
element.requestPointerLock();

// Ask the browser to release the pointer
document.exitPointerLock = document.exitPointerLock ||
               document.mozExitPointerLock ||
               document.webkitExitPointerLock;
document.exitPointerLock();

Sie müssen lediglich den obigen Code ausführen. Wenn der Browser den Zeiger sperrt, erscheint ein Infofeld, das den Nutzer darüber informiert, dass Ihre Anwendung den Zeiger gesperrt hat, und weist ihn an, den Zeiger durch Drücken der Esc-Taste abzubrechen.

Infoleiste für Zeigersperre in Chrome.
Pointer Lock-Infoleiste in Chrome

Ereignisverarbeitung

Es gibt zwei Ereignisse, für die Ihre Anwendung Listener hinzufügen muss. Die erste ist pointerlockchange, die immer dann ausgelöst wird, wenn sich der Zeigersperre-Zustand ändert. Die zweite ist mousemove und wird immer dann ausgelöst, wenn die Maus bewegt wird.

// Hook pointer lock state change events
document.addEventListener('pointerlockchange', changeCallback, false);
document.addEventListener('mozpointerlockchange', changeCallback, false);
document.addEventListener('webkitpointerlockchange', changeCallback, false);

// Hook mouse move events
document.addEventListener("mousemove", this.moveCallback, false);

In Ihrem pointerlockchange-Callback müssen Sie prüfen, ob der Cursor gerade gesperrt oder entsperrt wurde. Das Ermitteln, ob die Zeigersperre aktiviert war, ist einfach: Prüfen Sie, ob „document.pointerLockElement“ dem Element entspricht, für das die Zeigersperre angefordert wurde. Ist dies der Fall, hat Ihre Anwendung den Zeiger erfolgreich gesperrt. Ist dies nicht der Fall, wurde der Zeiger vom Nutzer oder Ihrem eigenen Code entsperrt.

if (document.pointerLockElement === requestedElement ||
  document.mozPointerLockElement === requestedElement ||
  document.webkitPointerLockElement === requestedElement) {
  // Pointer was just locked
  // Enable the mousemove listener
  document.addEventListener("mousemove", this.moveCallback, false);
} else {
  // Pointer was just unlocked
  // Disable the mousemove listener
  document.removeEventListener("mousemove", this.moveCallback, false);
  this.unlockHook(this.element);
}

Wenn die Zeigersperre aktiviert ist, bleiben clientX, clientY, screenX und screenY konstant. movementX und movementY werden mit der Anzahl der Pixel aktualisiert, die der Zeiger seit der Bereitstellung des letzten Ereignisses verschoben hätte. In Pseudocode:

event.movementX = currentCursorPositionX - previousCursorPositionX;
event.movementY = currentCursorPositionY - previousCursorPositionY;

Im mousemove-Callback können relative Mausbewegungsdaten aus den movementX- und movementY-Feldern des Ereignisses extrahiert werden.

function moveCallback(e) {
  var movementX = e.movementX ||
      e.mozMovementX          ||
      e.webkitMovementX       ||
      0,
  movementY = e.movementY ||
      e.mozMovementY      ||
      e.webkitMovementY   ||
      0;
}

Fehler beim Abfangen

Wenn durch Eingabe oder Beenden der Zeigersperre ein Fehler ausgelöst wird, wird das pointerlockerror-Ereignis ausgelöst. An diesen Termin wurden keine Daten angehängt.

document.addEventListener('pointerlockerror', errorCallback, false);
document.addEventListener('mozpointerlockerror', errorCallback, false);
document.addEventListener('webkitpointerlockerror', errorCallback, false);

Vollbild erforderlich?

Ursprünglich war die Zeigersperre mit der FullScreen API verbunden. Das bedeutet, dass sich ein Element im Vollbildmodus befinden muss, bevor der Zeiger an dieses Element gebunden werden kann. Dies ist nicht mehr der Fall und die Zeigersperre kann für jedes Element in Ihrer Anwendung im Vollbildmodus verwendet werden oder nicht.

Beispiel für Ego-Shooter

Da wir nun die Zeigersperre aktiviert und Ereignisse empfangen, ist es Zeit für ein praktisches Beispiel. Wollten Sie schon einmal wissen, wie die Quake-Steuerung funktioniert? Also schnappt euch drauf, denn ich werde sie euch jetzt mit Code erklären!

Die Steuerelemente für Ego-Shooter basieren auf vier Grundelementen:

  • Vorwärts und rückwärts entlang des aktuellen Lookvektors
  • Entlang des aktuellen Strafe-Vektors nach links und rechts bewegen
  • Gierwinkel der Ansicht drehen (links und rechts)
  • Neigung der Ansicht nach oben und unten drehen

Ein Spiel, das dieses Steuerschema implementiert, benötigt nur drei Daten: die Kameraposition, den Kameralookvektor und einen Konstantenvektor. Der Aufwärtsvektor ist immer (0, 1, 0). Alle vier der oben genannten Mechaniken verändern lediglich die Kameraposition und den Kameraschauvektor auf unterschiedliche Weise.

Stilrichtung

Zuerst kommt Bewegung. In der folgenden Demo wird Bewegung den Standardtasten W, A, S und D zugeordnet. Mit den Tasten W und S bewegen Sie die Kamera vor und zurück. Mit den Tasten A und D bewegen Sie die Kamera dagegen nach links und rechts. Sie können die Kamera ganz einfach vor- und zurückbewegen:

// Forward direction
var forwardDirection = vec3.create(cameraLookVector);
// Speed
var forwardSpeed = dt * cameraSpeed;
// Forward or backward depending on keys held
var forwardScale = 0.0;
forwardScale += keyState.W ? 1.0 : 0.0;
forwardScale -= keyState.S ? 1.0 : 0.0;
// Scale movement
vec3.scale(forwardDirection, forwardScale * forwardSpeed);
// Add scaled movement to camera position
vec3.add(cameraPosition, forwardDirection);

Das Strafen nach links und rechts erfordert eine Strafe-Richtung. Die Strafe-Richtung kann mit dem Kreuzprodukt berechnet werden:

// Strafe direction
var strafeDirection = vec3.create();
vec3.cross(cameraLookVector, cameraUpVector, strafeDirection);

Sobald Sie die Strafe-Richtung festgelegt haben, ist die Implementierung des Strafe-Bewegung dasselbe wie das Vorwärts- oder Rückwärtsgehen.

Als Nächstes drehen Sie die Ansicht.

Gieren

Gier- oder horizontale Drehung der Kameraansicht ist nur eine Drehung um den konstanten Aufwärtsvektor. Im Folgenden finden Sie einen allgemeinen Code zum Drehen des Kamerablickvektors um eine beliebige Achse. Dabei wird ein Quaternion konstruiert, das die Drehung von deltaAngle Radiant um axis darstellt. Anschließend wird mit dem Quaternion der Kamerablickvektor gedreht:

// Extract camera look vector
var frontDirection = vec3.create();
vec3.subtract(this.lookAtPoint, this.eyePoint, frontDirection);
vec3.normalize(frontDirection);
var q = quat4.create();
// Construct quaternion
quat4.fromAngleAxis(deltaAngle, axis, q);
// Rotate camera look vector
quat4.multiplyVec3(q, frontDirection);
// Update camera look vector
this.lookAtPoint = vec3.create(this.eyePoint);
vec3.add(this.lookAtPoint, frontDirection);

Pitchen

Die Implementierung der Neigung bzw. der vertikalen Drehung der Kameraansicht erfolgt ähnlich, allerdings wenden Sie statt einer Drehung um den Vektor nach oben eine Drehung um den Strafe-Vektor an. Der erste Schritt besteht darin, den Strafe-Vektor zu berechnen und dann den Kamerablickvektor um diese Achse zu drehen.

Zusammenfassung

Mit der Pointer Lock API können Sie den Mauszeiger steuern. Wenn du Webspiele entwickelst, werden deine Spieler begeistert sein, wenn sie nicht mehr fragwürdig sind, weil sie aufgeregt die Maus aus dem Fenster bewegt haben und dein Spiel keine Maus-Updates mehr erhält. Die Verwendung ist einfach:

  • pointerlockchange-Event-Listener hinzufügen, um den Status der Zeigersperre zu verfolgen
  • Zeigersperre für ein bestimmtes Element anfordern
  • mousemove-Event-Listener hinzufügen, um Updates zu erhalten

Externe Demos

Verweise