Eigene Komponenten für A-Frame programmieren

In den letzten beiden Artikeln haben wir uns mit den Grundlagen des flexiblen Objekt- Komponenten Systems von A-Frame beschäftigt.

Mit diesem Verständnis können wir uns heute daran machen eigene Komponenten zu programmieren!

Falls du die vorherigen Artikel zu A-Frame noch nicht gelesen hast und noch wenig von diesem neuen Framework weißt, dann empfehle ich dir diese zu lesen bevor du dich an eine eigene Komponenten machst.

Außerdem solltest du dich recht gut mit der Programmiersprache JavaScript auskennen um diesem Tutorial folgen zu können.

WebVR mit A-Frame: Einführung & Grundlagen

Schneller Einstieg in die WebVR Entwicklung mit A-Frame

Das Objekt-Komponenten System von A-Frame verstehen


Grundaufbau

Um unsere neue, eigene Komponente wie jede andere A-Frame Komponente direkt im HTML Markup verwenden zu können, müssen wir sie erst beim Core registrieren und ihr einen Namen geben.

Diesen Schritt macht uns das Framework durch folgende Funktion sehr einfach:

AFRAME.aframeCore.registerComponent("weatherlog", { /* ... */ });

Neben dem Namen weatherlog müssen wir als zweiten Parameter die Definition unserer Komponente angeben. Dabei geben wir an welche Eigenschaften wir ihr geben wollen und wie sie sich in den verschiedenen Lebenszyklen verhalten soll.

Die Eigenschaften legen wir über das schema-Objekt fest. Jede Eigenschaft kann dabei einen Standard-Wert enthalten.

schema: {
  state: { default: "sonnig" },
  celsius: { default: 20 }
}

In diesem Beispiel geben wir unserer Wetterbericht-Komponente die Eigenschaften state und celcius, jeweils mit Standard-Werten. Diese können wir dann beim Einbinden überschreiben – zum Beispiel so:

<a-entity weatherlog="celsius: 32"></a-entity>

Damit haben wir das weatherlog mit 32°C beschrieben, aber den Status auf dem Standard "sonnig" belassen. So, nun haben wir unsere eigene Komponente mit Eigenschaften definiert… aber sie macht ja noch gar nichts! Das Verhalten und die Interaktion mit anderen Komponenten gehen wir als nächstes an.

Lebenszyklus einer Komponente

Hierzu bietet uns A-Frame einige Funktionen an, die den Lebenszyklus einer Komponente beschreiben und die wir für unsere Zwecke verwenden können.

Aktuell sind das init, update und remove. In der nächsten Version wird sich diese API ein wenig verändern – sobald diese verfügbar ist, werde ich über das Newsletter eine Überarbeitung nachliefern.

Die init Methode wird einmalig aufgerufen, sobald die Komponente an ein Objekt gebunden wird. Verwende diese Methode für das initiale Setup, die Vorbereitungen.

Die update Methode wird erstmalig aufgerufen, wenn die Komponente an ein Objekt gebunden wird (im Anschluss an die init Methode) und dann jedes Mal, wenn sich die Eigenschaften verändern oder — falls du es so eingestellt hast — bei jedem Frame. In der Regel verwendest du diese Methode um auf den gegebenen Daten das Objekt zu verändern oder neue Objekte hinzuzufügen.

Die remove Methode wird einmalig aufgerufen, sobald die Komponente aus der Szene entfernt wurde (z.B. durch removeAttribute) – im Grunde sind das ihre letzten Worte bevor sie "stirbt". :) An dieser Stelle solltest du alle Änderungen am Objekt wieder rückgängig machen.

Lass uns die init und update Methoden am Beispiel unserer weatherlog-Komponente einmal beispielsweise zum besseren Verständnis verwenden:

init: function () {
  console.log("weatherlog ist bereit!");
},

update: function () {
  var state = this.data.state;
  var celcius = this.data.celcius;

  console.log("Heute ist es "+state+" bei "+celcius+"°C. []-)");
}

Wenn wir weatherlog in unser Projekt einbinden und verwenden, erhalten dieses Ergebnis in der JavaScript Konsole:

weatherlog ist bereit!
Heute ist es sonnig bei 32°C. []-)

Mit diesem Grundwissen hast du schon die wichtigsten Elemente kennengelernt um eigene Komponenten für A-Frame zu programmieren. Als nächstes sehen wir uns einmal ein konkretes Beispiel an, das über die einfachen Logs hinausgeht!


Der Randomator

Die neue Komponente nennen wir den randomator. Seine Aufgabe ist ganz simpel: Das Objekt in einem definierten Bereich zufällig positionieren.

Nicht sehr spektakulär, aber ideal um etwas tiefer in das System einzutauchen und die nächsten Schritte zu verstehen.

Unser schema sieht erstmal sehr einfach aus. Der Komponente kann der Grenzwert – also wie weit das Objekt maximal positioniert werden kann – über den threshold übergeben werden.

schema: {
  threshold: { default: 1.0 }
}

Unsere update Methode wird etwas umfangreicher, schauen wir uns einmal den ganzen Code an und gehen dann die Zeilen einzeln durch:

update: function () {
  var obj = this.el.object3D;
  var th = this.data.threshold;

  var x = Math.random()*th;
  var y = Math.random()*th;
  var z = Math.random()*th;

  obj.position.set(x, y, z);
}

Über this.el.object3D können wir auf das Objekt zugreifen, auf das die Komponente angewendet wurde. Und über this.data können wir die Eigenschaften abrufen, in dem Fall schnappen wir uns den Grenzwert per this.data.threshold.

In Zeile 5, 6 und 6 definieren wir die neue Position auf allen drei Koordinaten. Dabei multiplizieren wir jeweils den Grenzwert mit einer zufälligen Zahl — Math.random() gibt eine Zahl zwischen 0 und 1.0 zurück.

Schließlich setzen wir die Position des Objekts auf die zufälligen Koordinaten. Und das war es auch schon! Jedes A-Frame-Objekt, dem du diese Komponente anfügst, wird nun zufällig — innerhalb des Grenzwertes — positioniert.

<a-cube randomator="threshold: 3"></a-cube>

Lass uns noch einen Schritt weiter gehen und die Komponente bei jedem neuen Bildaufbau das Objekt neu und zufällig positionieren. Damit diese Möglichkeit optional ist, fügen wir noch eine weitere Eigenschaft hinzu:

nervous: { default: false }

Außerdem erweitern wir unsere init Methode:


init: function () {
  if (this.data.nervous) {
    this.el.sceneEl.addBehavior(this);
  }
}

In dieser fragen wir ab, ob die nervous Eigenschaft positiv ist. Und falls ja, geben wir dem Framework den Hinweis — über this.el.sceneEl.addBehavior(this) — die update Methode unserer Komponente bei jedem Frame (bzw. Tick) wieder aufzurufen.

Nun müssen wir nur noch nervous auf true setzen um den Effekt zu sehen:

<a-cube randomator></a-cube>
<a-sphere randomator="nervous: true"></a-sphere>
Sieht wild aus, was unsere Komponente mit der Kugel macht... []-)

Alle Dateien für dieses Beispiel findest du hier auf Github.


Zusätzliche Möglichkeiten

A-Frame bietet noch viele weitere Möglichkeiten für die Programmierung von Komponenten an. Zum Beispiel können die Schemas noch genauer spezifiziert werden, sodass nur eine Auswahl von Angaben möglich sind oder manche Eigenschaften mit anderen zusammen hängen.

Auch kannst du innerhalb einer Komponente auf andere Komponenten des Objekts zugreifen und sogar Abhängigkeiten (sogenannte dependencies) definieren. Zusätzlich kannst du auf externe Events hören und eigene senden.

Wenn dich diese Details interessieren, kannst du dir die Dokumentation von A-Frame genauer ansehen oder den Code einiger Core-Komponenten auf GitHub durchlesen.

Nächste Schritte

Aber sehr gerne kannst du mich direkt kontaktieren und deine Fragen stellen. Oder solltest du bei deinem Projekt einmal fest stecken oder selbst keine Zeit haben es umzusetzen, stehe ich dir gerne zur Verfügung. Ich biete auch regelmäßige (Inhouse-)Trainings zur VR-Entwicklung an – auch zu WebVR bzw. A-Frame.

Sehr hilfreich für deine eigenen Komponenten ist die Vorlage von Kevin Ngo – das Boilerplate Projekt für A-Frame findest du ebenfalls auf GitHub.

A-Frame für erfahrene Programmierer*innen

Bisher haben wir uns in der Artikelreihe zu A-Frame auf die Grundlagen und einfachen Bereiche konzentriert. Dabei kann schnell der Eindruck entstehen, dass A-Frame eher etwas für Einsteiger ist und nichts für erfahrene Programmierer*innen oder größere und komplexe Projekte.

Genau das Gegenteil ist aber der Fall: A-Frame ermöglicht vor allem in umfangreicheren Projekten eine saubere Struktur und langfristige Erweiterbarkeit. Ich hatte hierzu schon die Integration mit dem React Framework angesprochen.

Im letzten Artikel der Serie zu A-Frame, der kommenden Dienstag veröffentlicht wird, sehen wir uns an, wie du mit JavaScript direkt auf die Komponenten zugreifen und so ganz individuelle Interaktionen in "klassischem" JS-Code ermöglichen kannst.

Freu dich drauf und solltest du es noch nicht gemacht haben: Eine kurze Anmeldung beim Newsletter garantiert dir eine freundliche Erinnerung in deinem Postfach, sobald der Artikel online ist!