Zum Hauptinhalt springen

Laufzeitcode

Geben Sie Ihrem Plugin Code, der im veröffentlichten Projekt läuft: Systeme, die Objekte bewegen, Trigger und Schritte für Ereignisse und Einstellungen für das ganze Projekt.

Panels und eigene Komponenten arbeiten im Editor. Laufzeitcode läuft überall, wo das Projekt abgespielt wird: im veröffentlichten Projekt im Web und in der App, in der Vorschau des Editors und in Playtests.

Laufzeitcode hinzufügen​

Lassen Sie runtime im Manifest auf eine .ts- oder .js-Datei in Ihrem Plugin-Ordner zeigen:

{
"id": "acme.spin",
"name": "Spin",
"version": "1.0.0",
"entry": "main.tsx",
"permissions": [],
"panels": [],
"components": [{ "id": "spin", "title": "Spin", "entry": "spin.tsx" }],
"runtime": "runtime/index.ts"
}

Die Datei läuft einmal beim Start des Projekts, neben den Skripten des Projekts. Registrieren Sie dort ein System. Ein System läuft in jedem Frame:

// runtime/index.ts
import { Collection, System } from '@was/ecs';
import { TransformComponent, frameTime, pluginComponent } from '@was/engine';

class AcmeSpinSystem extends System.from('AcmeSpinSystem') {
execute() {
const { dt } = frameTime();
const spin = pluginComponent('acme.spin/spin', this.space);
for (const e of spin.entities()) {
const t = e.getComponent(TransformComponent)!;
const r = t.$data.rotation;
t.update({ rotation: { ...r, y: r.y + (spin.props(e)!.speed as number) * dt } });
}
}
}
Collection.registerSystem(AcmeSpinSystem);

Dieses System dreht jedes Objekt, das die Komponente Spin des Plugins hat, mit der Geschwindigkeit, die im Inspektor eingestellt ist.

Benennen Sie Systeme nach Ihrem Plugin

Alles im Projekt teilt sich dieselben Systemnamen. Ist ein Name schon vergeben, startet Ihr System nicht, und die Fehlermeldung nennt den Namen. Beginnen Sie jeden Namen mit dem Namen Ihres Plugins, etwa AcmeSpinSystem.

Was Laufzeitcode nutzen kann​

Laufzeitcode kann dasselbe importieren wie ein Skript: @was/ecs, @was/engine, @was/utils und @was/svdt. Ausgeliefert werden nur die Einstiegsdatei und die Dateien, die sie mit ./ importiert, zusammen bis zu 1 MB.

Er hat keine Seite, kein DOM, kein three.js und kein React. Er liest und ändert Komponenten, und die Engine zeichnet das Ergebnis.

FunktionWas Sie bekommen
frameTime(){ dt, t }: die Zeit seit dem letzten Frame und seit dem Start, in Sekunden
pluginComponent(key, space)Ihre eigene Komponente an Objekten: lesen und ändern
pluginEvents(id, space)Ihre Trigger auslösen und auf Ihre Schritte antworten
pluginSettings(id)die Werte, die das Projekt für Ihre Einstellungen gewählt hat
pluginContext(id, space)den ctx der Skripte: Eingabe, Physik, Strahlen, Ton, globale Werte, Mehrspieler

key ist <plugin id>/<component id>, etwa acme.spin/spin. id ist die id des Plugins aus dem Manifest.

Ihre Komponente​

pluginComponent(key, space) gibt Ihnen:

MethodeWas sie tut
entities()die Objekte, die die Komponente haben
has(e)ob die Komponente an diesem Objekt eingeschaltet ist
props(e)die Werte aus dem Inspektor, mit Standardwerten
state(e)der eigene Zustand der Komponente
setState(e, patch)ändert den Zustand
setProps(e, patch)ändert die Werte im Inspektor
setEnabled(e, on)schaltet die Komponente ein oder aus
add(e, props)fügt die Komponente einem Objekt hinzu
remove(e)entfernt sie

Skripte bekommen dasselbe als ctx.plugin(key).

Der Skript-Kontext​

pluginContext(id, space) gibt denselben ctx zurück, den auch ein Skript bekommt: für Eingabe, Physik, Raycasts, Audio, globale Werte und Mehrspieler. Bis die Skripte des Projekts starten, ist er null, und er kann sich ändern, wenn sich die Welt ändert. Holen Sie ihn sich also erst, wenn Sie ihn brauchen. ctx.on und ctx.tick fügen bei jedem Aufruf einen neuen Handler hinzu. Abonnieren Sie deshalb für jeden Kontext nur einmal.

Trigger und Schritte​

Ein Plugin mit Laufzeitcode kann dem Panel Ereignisse eigene Trigger und Schritte hinzufügen. Dann nutzt man sie ohne Code, wie die eingebauten. Sie erscheinen unter dem Namen Ihres Plugins, in Projekten, die das Plugin haben.

Deklarieren Sie sie im Manifest:

"triggers": [
{ "id": "reached", "title": "Reached a point",
"params": { "point": { "type": "number", "default": -1, "any": -1, "label": "Point" } } }
],
"steps": [
{ "id": "pause", "title": "Pause",
"params": { "seconds": { "type": "number", "default": 0, "min": 0 } } }
]
  • IDs werden in kebab-case geschrieben. Der vollständige Name ist <plugin id>:<id>, etwa acme.patrol:reached.
  • params nutzen die Feldtypen von defineProps: number, string, boolean, color, select, entity und resource. Das Panel zeichnet daraus ein Formular.
  • Die Parameter eines Triggers wirken als Filter. Ein Ereignis, das auf Punkt 2 eingestellt ist, läuft nur, wenn der Trigger mit point: 2 ausgelöst wird. Ein leerer Parameter oder einer mit seinem any-Wert lässt jede Auslösung durch.

Lösen Sie die Trigger in Ihrem Laufzeitcode aus und antworten Sie dort auf die Schritte:

import { pluginEvents } from '@was/engine';

class AcmePatrolSystem extends System.from('AcmePatrolSystem') {
events = pluginEvents('acme.patrol', this.space);
off = this.events.onStep<{ seconds: number }>('pause', (targets, params) => {
// die Objekte in `targets` für params.seconds anhalten
});

execute() {
// wenn eine Wache einen Punkt erreicht:
// this.events.fire('reached', guard, { point: 2 });
}

dispose() {
this.off();
}
}
  • fire(id, object, payload) führt die Ereignisse aus, die diesen Trigger nutzen, an diesem Objekt und an den Objekten darüber. Ohne Objekt wird er überall ausgelöst. Skripte hören ihn als ctx.on('acme.patrol:reached', payload => …).
  • onStep(id, handler) läuft, wenn ein Ereignis Ihren Schritt ausführt. Auch ein Skript kann ihn ausführen, mit ctx.step('acme.patrol:pause', { seconds: 2 }). Abonnieren Sie nur einmal, und rufen Sie die zurückgegebene Funktion in dispose() auf.
  • Wird das Plugin aus einem Projekt entfernt, werden seine Trigger nie ausgelöst und seine Schritte übersprungen.

Projekteinstellungen​

Manche Werte gehören zum ganzen Projekt: ein Tempo, ein Schwierigkeitsgrad, eine Farbe. Deklarieren Sie sie unter settings: bis zu 24 Felder der Typen number, string, boolean, color und select.

"settings": {
"tempo": { "type": "number", "default": 1, "min": 0, "label": "Tempo" }
}

Eingestellt werden sie in den Projekteinstellungen, in einem Bereich mit dem Namen Ihres Plugins.

  • Laufzeitcode liest sie mit pluginSettings<{ tempo: number }>('acme.patrol'). Sie bekommen jedes Feld: den Wert des Projekts oder den Standardwert. Die Werte sind bereit, bevor Ihre Einstiegsdatei läuft, und ändern sich nicht, während das Projekt läuft.
  • Ein veröffentlichtes Projekt nutzt die Werte, mit denen es veröffentlicht wurde.
  • Ihr Panel liest und ändert sie mit editor.pluginSettings.get() und editor.pluginSettings.set({ tempo: 2 }). Dafür braucht es die Berechtigung settings:write.

So kommt der Code ins Projekt​

Laufzeitcode läuft nur in Projekten, denen das Plugin hinzugefügt wurde.

  • Das Hinzufügen legt die Version fest. Das Projekt behält den Code, den das Plugin in diesem Moment hatte. Vorschau, Playtests und Veröffentlichungen führen diesen Code aus, auch nachdem Sie eine neuere Version veröffentlicht haben.
  • Aktualisieren ist eine bewusste Wahl. Gibt es neueren Code, zeigt das Plugin im Panel Plugins den Hinweis Update verfügbar. Im Projekt aktualisieren stellt das Projekt darauf um.
  • Ihre eigenen Projekte gehen mit. Haben Sie Ihr eigenes Plugin einem Projekt hinzugefügt, führt das Projekt jede Version aus, die Sie speichern.
  • Eine Veröffentlichung behält ihren Code. Ein veröffentlichtes Projekt führt den Code aus, mit dem es veröffentlicht wurde, bis es erneut veröffentlicht wird.

Titel, Beschreibungen und Beschriftungen in Triggern, Schritten und Einstellungen können aus Ihren Sprachdateien kommen, geschrieben als ${…}.

Plugins nur für Abonnenten​

Der Laufzeitcode eines Plugins geht an alle, die das veröffentlichte Projekt öffnen, und jeder kann ihn in seinem Browser lesen. Das gilt auch für ein Plugin mit dem Zugriff Nur für Abonnenten. Das Abonnement entscheidet, wer das Plugin einem Projekt hinzufügen, es aktualisieren und damit veröffentlichen kann. Den Code verbirgt es nicht.

Endet das Abonnement, kann ein Projekt, das das Plugin nutzt, nicht erneut veröffentlicht werden. Verlängern Sie das Abonnement oder entfernen Sie das Plugin. Ein bereits veröffentlichtes Projekt funktioniert weiter.

Für Entwickler​

  • Laufzeitcode läuft im Skript-Worker des Projekts, zusammen mit den Skripten des Projekts.
  • Die Version, die ein Projekt behält, ist ein Fingerabdruck der Laufzeitdateien, der Trigger, der Schritte und der Einstellungen. Bei einem anderen Fingerabdruck erscheint Update verfügbar.

Weiter: Tastenkürzel – die Tasten, mit denen Sie schneller arbeiten.