Код в проекте
Дайте плагину код, который работает в опубликованном проекте: системы, которые двигают объекты, триггеры и шаги для событий и настройки для всего проекта.
Панели и свои компоненты работают в редакторе. Код в проекте работает везде, где проект запускается: в опубликованном проекте в браузере и в приложении, в предпросмотре редактора и в плейтестах.
Добавьте код
Укажите в поле runtime манифеста файл .ts или .js из папки плагина:
{
"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"
}
Файл выполняется один раз при старте проекта, рядом со скриптами проекта. Зарегистрируйте в нём систему. Система работает каждый кадр:
// 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);
Эта система вращает каждый объект с компонентом плагина Spin со скоростью, заданной в инспекторе.
Имена систем общие для всего проекта. Если имя уже занято, ваша система не запустится, а в ошибке
будет сказано, какое имя. Начинайте каждое имя с названия плагина, как AcmeSpinSystem.
Что доступно коду
Код в проекте может импортировать то же, что и скрипт: @was/ecs, @was/engine, @was/utils и
@was/svdt. В проект попадает только входной файл и файлы, которые он импортирует через ./, —
всего до 1 МБ.
У этого кода нет страницы, DOM, three.js и React. Он читает и меняет компоненты, а движок рисует результат.
| Функция | Что даёт |
|---|---|
frameTime() | { dt, t }: время с прошлого кадра и с начала, в секундах |
pluginComponent(key, space) | ваш компонент на объектах: читать и менять его |
pluginEvents(id, space) | запускать ваши триггеры и отвечать на ваши шаги |
pluginSettings(id) | значения ваших настроек, которые выбрал проект |
pluginContext(id, space) | ctx скрипта: ввод, физика, лучи, звук, глобальные значения, мультиплеер |
key — это <plugin id>/<component id>, например acme.spin/spin. id — поле id плагина из
манифеста.
Ваш компонент
pluginComponent(key, space) даёт:
| Метод | Что делает |
|---|---|
entities() | объекты, у которых есть компонент |
has(e) | включён ли компонент у объекта |
props(e) | значения из инспектора, со значениями по умолчанию |
state(e) | собственное состояние компонента |
setState(e, patch) | меняет состояние |
setProps(e, patch) | меняет значения инспектора |
setEnabled(e, on) | включает или выключает компонент |
add(e, props) | добавляет компонент объекту |
remove(e) | убирает его |
Скрипты получают то же самое через ctx.plugin(key).
Контекст скрипта
pluginContext(id, space) возвращает тот же ctx, что получает скрипт: ввод, физика, лучи, звук,
глобальные значения и мультиплеер. До старта скриптов проекта он равен null и может смениться
вместе с миром, поэтому запрашивайте его, когда он нужен. ctx.on и ctx.tick добавляют новый
обработчик при каждом вызове, поэтому подписывайтесь один раз на каждый контекст.
Триггеры и шаги
Плагин с кодом в проекте может добавить свои триггеры и шаги в панель событий. Ими пользуются без кода, как встроенными. Они появляются под названием плагина в проектах, где он есть.
Объявите их в манифесте:
"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 } } }
]
- Id пишутся в kebab-case. Полное имя —
<plugin id>:<id>, напримерacme.patrol:reached. paramsиспользуют типы полейdefineProps:number,string,boolean,color,select,entityиresource. Панель рисует для них форму.- Параметры триггера фильтруют. Событие с точкой 2 сработает, только когда триггер запущен с
point: 2. Пустой параметр или параметр со значениемanyпропускает любой запуск.
Запускайте триггеры и отвечайте на шаги из кода плагина:
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) => {
// остановить объекты из `targets` на params.seconds
});
execute() {
// когда охранник дошёл до точки:
// this.events.fire('reached', guard, { point: 2 });
}
dispose() {
this.off();
}
}
fire(id, object, payload)запускает события с этим триггером на объекте и на объектах выше него. Без объекта триггер срабатывает везде. Скрипты слышат его какctx.on('acme.patrol:reached', payload => …).onStep(id, handler)вызывается, когда событие выполняет ваш шаг. Скрипт тоже может его выполнить:ctx.step('acme.patrol:pause', { seconds: 2 }). Подпишитесь один раз, а возвращённую функцию вызовите вdispose().- Если плагин убрали из проекта, его триггеры больше не срабатывают, а шаги пропускаются.
Настройки проекта
Некоторые значения относятся ко всему проекту: темп, сложность, цвет. Объявите их в settings: до
24 полей типов number, string, boolean, color и select.
"settings": {
"tempo": { "type": "number", "default": 1, "min": 0, "label": "Tempo" }
}
Их задают в настройках проекта, в разделе с названием плагина.
- Код в проекте читает их через
pluginSettings<{ tempo: number }>('acme.patrol'). Вы получаете все поля: значение проекта или значение по умолчанию. Значения готовы до запуска входного файла и не меняются, пока проект работает. - Опубликованный проект использует значения, с которыми его опубликовали.
- Панель плагина читает и меняет их через
editor.pluginSettings.get()иeditor.pluginSettings.set({ tempo: 2 }). Для этого нужно правоsettings:write.
Как код попадает в проект
Код работает только в проектах, в которые добавлен плагин.
- Добавление фиксирует версию. Проект сохраняет код, который был у плагина в этот момент. Предпросмотр, плейтесты и публикации запускают этот код, даже когда вы опубликовали новый.
- Обновление — по желанию. Когда есть код новее, у плагина в панели Плагины появляется пометка есть обновление. Кнопка Обновить в проекте переводит проект на него.
- Ваши проекты идут за вами. Если вы добавили свой плагин в проект, проект запускает каждую версию, которую вы сохраняете.
- Публикация хранит свой код. Опубликованный проект запускает код, с которым его опубликовали, до следующей публикации.
Названия, описания и подписи триггеров, шагов и настроек можно брать из
словарей плагина — пишите их как ${…}.
Плагины для подписчиков
Код плагина попадает ко всем, кто открывает опубликованный проект, и любой может прочитать его в браузере. Это верно и для плагина с доступом Только подписчикам. Подписка решает, кто может добавить плагин в проект, обновить его и опубликовать проект с ним. Код она не скрывает.
Если подписка закончилась, проект с этим плагином больше нельзя опубликовать заново. Продлите подписку или уберите плагин. Уже опубликованный проект продолжает работать.
Для разработчиков
- Код в проекте выполняется в воркере скриптов проекта, вместе со скриптами проекта.
- Версия, которую хранит проект, — это отпечаток файлов кода, триггеров, шагов и настроек. Другой отпечаток показывает пометку есть обновление.
Дальше: Горячие клавиши — клавиши, с которыми работать быстрее.