Start · Sprachen · JavaScript · Referenz · XRInputSourceArray.forEach()

XRInputSourceArray.forEach()

Methode

Führt einen Callback einmal für jede <code>XRInputSource</code> im <code>XRInputSourceArray</code> aus, in Index-Reihenfolge von 0 bis zum Ende.

seit JavaScript WebXR Device API – Chromium-basierte Browser (Chro Kategorie: webapi

Signatur

XRInputSourceArray.prototype.forEach(callback, thisArg)

Beschreibung

Die Methode forEach() von XRInputSourceArray durchläuft alle aktuell mit einer XRSession verbundenen Eingabequellen – etwa Hand-Controller, getrackte Hände, Blick-Eingaben (Gaze) oder Bildschirm-Touches bei AR. Für jede Eingabequelle wird der übergebene Callback mit dem Element, seinem Index und dem Array selbst aufgerufen.

Ein XRInputSourceArray erhält man über XRSession.inputSources. Es ist kein echtes Array, sondern ein Array-ähnliches, live aktualisiertes Objekt mit length, Index-Zugriff sowie den Methoden entries(), keys(), values() und forEach(). Methoden wie map() oder filter() stehen nicht direkt zur Verfügung.

Typischerweise nutzt man forEach() innerhalb des Render-Loops (requestAnimationFrame-Callback), um für jeden Controller die Pose per XRFrame.getPose() abzufragen, einen Zeigestrahl zu zeichnen oder Gamepad-Tasten auszuwerten.

Parameter

Name Typ Default Beschreibung
$callback Pflicht (currentValue: XRInputSource, currentIndex: number, sourceList: XRInputSourceArray) => void Funktion, die für jede Eingabequelle aufgerufen wird. Erhält currentValue (die aktuelle XRInputSource), currentIndex (deren Index) und sourceList (das durchlaufene XRInputSourceArray). Ein Rückgabewert wird ignoriert.
$thisArg any undefined Wert, der innerhalb von callback als this verwendet wird. Bei Pfeilfunktionen wirkungslos.

Beispiele

Alle Eingabequellen einer Sitzung auflisten

const session = await navigator.xr.requestSession('immersive-vr');

session.inputSources.forEach((source, index) => {
  console.log(`#${index}: ${source.handedness} / ${source.targetRayMode}`, source.profiles);
});
#0: left / tracked-pointer ['oculus-touch-v3', 'generic-trigger-squeeze-thumbstick'] #1: right / tracked-pointer ['oculus-touch-v3', 'generic-trigger-squeeze-thumbstick']

Zeigestrahl-Posen im Render-Loop abfragen

const onXRFrame = (time, frame) => {
  const session = frame.session;
  session.requestAnimationFrame(onXRFrame);

  session.inputSources.forEach((source) => {
    const pose = frame.getPose(source.targetRaySpace, refSpace);
    if (!pose) return; // Controller gerade nicht getrackt

    const { position } = pose.transform;
    drawRay(source.handedness, pose.transform.matrix);
    console.log(source.handedness, position.x.toFixed(2), position.y.toFixed(2), position.z.toFixed(2));
  });
};

let refSpace;
const session = await navigator.xr.requestSession('immersive-vr');
refSpace = await session.requestReferenceSpace('local');
session.requestAnimationFrame(onXRFrame);
right 0.21 -0.35 -0.42

Gamepad-Tasten aller Controller auswerten

const checkButtons = (session) => {
  session.inputSources.forEach((source) => {
    // Hand-Tracking oder Gaze liefern kein Gamepad
    if (!source.gamepad) return;

    const [trigger, squeeze] = source.gamepad.buttons;
    if (trigger?.pressed) {
      console.log(`Trigger gedrückt (${source.handedness})`);
    }
    if (squeeze?.pressed) {
      console.log(`Griff gedrückt (${source.handedness})`);
    }
  });
};
Trigger gedrückt (right)

Mit thisArg auf ein Zustandsobjekt schreiben

const stats = { hands: 0, controllers: 0 };

session.inputSources.forEach(function (source) {
  if (source.hand) this.hands++;
  else this.controllers++;
}, stats);

console.log(stats);
{ hands: 0, controllers: 2 }

// Wichtig · Fallstricke

  • Kein echtes Array: map(), filter() oder some() fehlen. Bei Bedarf mit Array.from(session.inputSources) oder Spread-Syntax [...session.inputSources] umwandeln.
  • Kein vorzeitiger Abbruch: return im Callback überspringt nur das aktuelle Element; break ist nicht möglich. Für Abbruch eine for...of-Schleife verwenden.
  • Live-Liste: Der Inhalt ändert sich, wenn Controller verbunden oder getrennt werden. Auf Änderungen reagiert man am besten über das Ereignis inputsourceschange der XRSession, statt Referenzen dauerhaft zu speichern.
  • Pose kann null sein: XRFrame.getPose() liefert null, wenn eine Quelle vorübergehend nicht getrackt wird – immer prüfen.
  • gamepad ist optional: Gaze-, Screen- und teils Hand-Eingaben haben kein gamepad-Objekt.
  • Kompatibilität: WebXR erfordert einen sicheren Kontext (HTTPS) und wird v. a. von Chromium-basierten Browsern und dem Meta Quest Browser unterstützt; Firefox und Safari (außer visionOS) bieten keine bzw. nur eingeschränkte Unterstützung. Die Methode ist als experimentell gekennzeichnet.
  • Performance: Im Render-Loop keine neuen Closures oder Objekte pro Frame anlegen, wenn es sich vermeiden lässt – das reduziert Garbage-Collection-Ruckler in VR.