Zum Hauptinhalt springen

Eigene Komponenten

Ein Plugin kann Objekten eine eigene Komponente hinzufügen. Ihre Oberfläche erscheint im Inspektor, neben Transformation und Material.

Das ist sinnvoll, wenn Ihr Werkzeug zu einem einzelnen Objekt gehört: Notizen zu einem Objekt, ein eigenes Bedienelement oder ein Generator, der bei dem bleibt, was er erzeugt. Ein solches Plugin braucht kein Panel.

Komponente deklarieren​

Führen Sie sie im Manifest unter components auf. panels darf leer sein:

{
"id": "entity-notes",
"entry": "main.tsx",
"panels": [],
"components": [{ "id": "notes", "title": "Notes", "entry": "main.tsx" }]
}

Komponente schreiben​

import {
Button,
Column,
Text,
defineProps,
useEntity,
useSignals,
useSyncedState,
} from '@was/extension';
import { TransformComponent } from '@was/engine';

const useProps = defineProps({ step: { type: 'number', default: 0.5 } });

export default function Notes() {
useSignals(); // neu rendern, wenn sich hier gelesene Szenendaten ändern
const props = useProps(); // Werte aus dem Formular im Inspektor
const entity = useEntity(); // das Objekt, an dem die Komponente hängt
const [note, setNote] = useSyncedState('note', '');

return (
<Column gap={2}>
<Text muted>{note}</Text>
<Button
onClick={() =>
setNote(`y=${entity.getComponent(TransformComponent)?.get('position').y}`)
}
>
Remember
</Button>
</Column>
);
}

Diese Hooks erledigen die Arbeit:

HookWas Sie bekommen
useEntity()das Objekt, an dem Ihre Komponente hängt
useWorld()die Szene, in der dieses Objekt liegt
useProps()die Werte aus dem Formular, das Sie mit defineProps deklariert haben
useSignals()ein neues Rendern, wenn sich Szenendaten ändern, die Sie beim Rendern gelesen haben
useSyncedState()Zustand, der am Objekt gespeichert und wie jede andere Komponente synchronisiert wird
useSelected()ob das Objekt im Editor ausgewählt ist
useViewportPointer()Mausereignisse im Viewport, mit dem Objekt und dem Punkt unter dem Zeiger

defineProps verwendet dieselben Feldtypen wie Skripteigenschaften: Zahl, Text, Boolean, Farbe, Auswahl, Objekt, Szene, Raum, Ressource, Datensatz, Liste und Gruppe. So bekommt Ihre Komponente ohne zusätzlichen Aufwand ein richtiges Formular im Inspektor.

Werte aus der Komponente ändern​

props.$set(patch) ändert die eigenen Felder Ihrer Komponente, so wie es der Inspektor tut: Die Änderung wird mit allen synchronisiert und lässt sich rückgängig machen. Sie wird gegen defineProps geprüft: Zahlen bleiben zwischen ihrem min und max, und ein Feld, das Sie nicht deklariert haben, löst einen Fehler aus. So können Sie einen Wert im Viewport ziehen:

<Handle axis={[0, 1, 0]} onDrag={(p) => props.$set({ height: p[1] })} />

Feldnamen, die mit $ beginnen, sind dafür reserviert, deshalb lehnt defineProps sie ab.

Zustand deklarieren​

defineState deklariert den Zustand der Komponente mit Standardwerten, so wie defineProps das Formular deklariert:

const useScore = defineState({ points: { type: 'number', default: 0 } });

const [score, setScore] = useScore(); // innerhalb der Komponente

Skripte lesen diesen Zustand dann typisiert, mit denselben Standardwerten.

Übersetzen​

i18n() oder useEditorLocale() aus @was/extension geben Ihnen t(key, vars) für die Sprachdateien Ihres Plugins, in der Sprache des Editors.

So läuft sie​

Ihre Komponente ist echtes React 19. Hooks, useEffect, Context und Suspense funktionieren wie gewohnt.

Der Editor zeichnet Ihre Komponente mit seinen eigenen Elementen. Deshalb sieht sie aus wie ein Teil des Editors.

Daraus folgen zwei Dinge:

  • Sie bauen nur aus den bereitgestellten Elementen. Beliebiges HTML ist nicht verfügbar. Im Inspektor: Column, Row, Text, Button, Divider, InputText, InputNumber, InputColor, Slider, Checkbox und Select. Im Viewport: Overlay, Gizmo, Group, Box, Sphere, Line, Handle und Control. Geben Sie einem Gizmo oder einem Overlay when="selected", damit es nur am ausgewählten Objekt erscheint.
  • Event-Handler schreiben Sie wie gewohnt. onClick funktioniert ganz normal. Nur ein DOM-Event können Sie nicht weiterreichen.

So wird sie hinzugefügt​

Ihre Komponente lässt sich auf zwei Wegen hinzufügen:

Hinzugefügt überErgebnis
+ neue Komponente, in der Gruppe Erweiterungensie wird dem bereits ausgewählten Objekt hinzugefügt
die Werkzeugleiste, unter +, in der Gruppe Pluginsein neues Objekt mit Ihrer Komponente wird erstellt und ausgewählt

Die Überschrift Plugins in der Werkzeugleiste zeigt, woher eine unbekannte Schaltfläche kommt.

Ein Plugin-Ordner, den Sie von Ihrem Computer verbunden haben, erscheint ebenfalls in dieser Liste der Werkzeugleiste, wenn er ein Panel hat. So öffnen Sie ihn, ohne jedes Mal über das Panel Plugins zu gehen. Ein Ordner, der nur ein Overlay enthält, erscheint dort nicht, weil es nichts zu öffnen gibt.

In Skripten und im veröffentlichten Projekt nutzen​

Die Oberfläche der Komponente funktioniert nur im Editor. Ihre Werte werden am Objekt gespeichert, sodass das Projekt sie nutzen kann, wenn es läuft:

  • Skripte lesen und ändern die Komponente mit ctx.plugin('<plugin id>/<component id>') → Die ctx-API;
  • der eigene Code Ihres Plugins für das veröffentlichte Projekt macht dasselbe → Laufzeitcode.

Vertrauen​

Sie startet ohne Klick

Eine eigene Komponente startet, sobald jemand ein Projekt öffnet, das sie enthält. Deshalb durchläuft sie die strengere Prüfung, die unter Vertrauen und Prüfung beschrieben ist.


Weiter: Laufzeitcode – damit Ihr Plugin auch im veröffentlichten Projekt funktioniert.