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.
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.
| Funktion | Was 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:
| Methode | Was 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>, etwaacme.patrol:reached. paramsnutzen die Feldtypen vondefineProps:number,string,boolean,color,select,entityundresource. 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: 2ausgelöst wird. Ein leerer Parameter oder einer mit seinemany-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 alsctx.on('acme.patrol:reached', payload => …).onStep(id, handler)läuft, wenn ein Ereignis Ihren Schritt ausführt. Auch ein Skript kann ihn ausführen, mitctx.step('acme.patrol:pause', { seconds: 2 }). Abonnieren Sie nur einmal, und rufen Sie die zurückgegebene Funktion indispose()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()undeditor.pluginSettings.set({ tempo: 2 }). Dafür braucht es die Berechtigungsettings: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.