Código de ejecución
Dale a tu plugin código que se ejecuta en el proyecto publicado: sistemas que mueven objetos, disparadores y pasos para los eventos, y ajustes para todo el proyecto.
Los paneles y los componentes personalizados funcionan en el editor. El código de ejecución funciona allí donde se reproduce el proyecto: en el proyecto publicado (en la web y en la app), en la vista previa del editor y en las pruebas de juego.
Añade código de ejecución
Apunta runtime en el manifiesto a un archivo .ts o .js de la carpeta de tu plugin:
{
"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"
}
El archivo se ejecuta una vez, cuando arranca el proyecto, junto a los scripts del proyecto. Registra ahí un sistema. Un sistema se ejecuta en cada fotograma:
// 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);
Este sistema hace girar todos los objetos que tienen el componente Spin del plugin, a la velocidad que se haya puesto en el inspector.
Todo el proyecto comparte los nombres de los sistemas. Si un nombre ya está ocupado, tu sistema no
arranca, y el error dice qué nombre es. Empieza cada nombre con el de tu plugin, como
AcmeSpinSystem.
Qué puede usar el código de ejecución
El código de ejecución puede importar lo mismo que un script: @was/ecs, @was/engine,
@was/utils y @was/svdt. Solo se envían el archivo de entrada y los archivos que importa con
./, hasta 1 MB en total.
No tiene página, ni DOM, ni three.js, ni React. Lee y cambia componentes, y el motor dibuja el resultado.
| Función | Qué te da |
|---|---|
frameTime() | { dt, t }: el tiempo desde el último fotograma y desde el inicio, en segundos |
pluginComponent(key, space) | tu componente personalizado en los objetos: para leerlo y cambiarlo |
pluginEvents(id, space) | para lanzar tus disparadores y responder a tus pasos |
pluginSettings(id) | los valores que el proyecto ha elegido para tus ajustes |
pluginContext(id, space) | el ctx de los scripts: entrada, física, rayos, sonido, globales, multijugador |
key es <plugin id>/<component id>, como acme.spin/spin. id es el id del plugin en el
manifiesto.
Tu componente
pluginComponent(key, space) te da:
| Método | Qué hace |
|---|---|
entities() | los objetos que tienen el componente |
has(e) | si el objeto lo tiene activado |
props(e) | los valores del inspector, con los valores por defecto |
state(e) | el estado propio del componente |
setState(e, patch) | cambia el estado |
setProps(e, patch) | cambia los valores del inspector |
setEnabled(e, on) | activa o desactiva el componente |
add(e, props) | añade el componente a un objeto |
remove(e) | lo quita |
Los scripts obtienen lo mismo con
ctx.plugin(key).
El contexto de los scripts
pluginContext(id, space) devuelve el mismo ctx que recibe un script, para la entrada, la
física, los raycasts, el audio, las globales y el multijugador. Es null hasta que arrancan los
scripts del proyecto, y puede cambiar cuando cambia el mundo, así que pídelo en el momento en que
lo necesites. ctx.on y ctx.tick añaden un manejador nuevo en cada llamada, así que suscríbete
una sola vez por cada contexto.
Disparadores y pasos
Un plugin con código de ejecución puede añadir sus propios disparadores y pasos al panel de eventos. Así la gente puede usarlos sin código, igual que los que vienen incluidos. Aparecen bajo el nombre de tu plugin, en los proyectos que tienen el plugin.
Decláralos en el manifiesto:
"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 } } }
]
- Los ids van en kebab-case. El nombre completo es
<plugin id>:<id>, comoacme.patrol:reached. paramsusa los tipos de campo dedefineProps:number,string,boolean,color,select,entityyresource. El panel dibuja un formulario para ellos.- Los params de un disparador sirven de filtro. Un evento configurado para el punto 2 solo se
ejecuta cuando el disparador se lanza con
point: 2. Un param vacío, o con su valorany, deja pasar todos los lanzamientos.
Lanza los disparadores y responde a los pasos desde tu código de ejecución:
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) => {
// detén los objetos de `targets` durante params.seconds
});
execute() {
// cuando un guardia llega a un punto:
// this.events.fire('reached', guard, { point: 2 });
}
dispose() {
this.off();
}
}
fire(id, object, payload)ejecuta los eventos que usan este disparador en ese objeto y en los objetos que tiene por encima. Sin objeto, se lanza en todas partes. Los scripts lo oyen conctx.on('acme.patrol:reached', payload => …).onStep(id, handler)se ejecuta cuando un evento ejecuta tu paso. Un script también puede ejecutarlo, conctx.step('acme.patrol:pause', { seconds: 2 }). Suscríbete una sola vez y llama a la función que te devuelve endispose().- Si se quita el plugin de un proyecto, sus disparadores ya no se lanzan nunca y sus pasos se saltan.
Ajustes del proyecto
Algunos valores son de todo el proyecto: un tempo, una dificultad, un color. Decláralos en
settings: hasta 24 campos de los tipos number, string, boolean, color y select.
"settings": {
"tempo": { "type": "number", "default": 1, "min": 0, "label": "Tempo" }
}
La gente los configura en Project settings, en una sección con el nombre de tu plugin.
- El código de ejecución los lee con
pluginSettings<{ tempo: number }>('acme.patrol'). Recibes todos los campos: el valor del proyecto o el valor por defecto. Los valores están listos antes de que se ejecute tu archivo de entrada y no cambian mientras se reproduce el proyecto. - Un proyecto publicado usa los valores con los que se publicó.
- Tu panel los lee y los cambia con
editor.pluginSettings.get()yeditor.pluginSettings.set({ tempo: 2 }). Para eso necesita el permisosettings:write.
Cómo llega el código a un proyecto
El código de ejecución solo se ejecuta en los proyectos a los que se ha añadido el plugin.
- Al añadir el plugin, la versión queda fijada. El proyecto se queda con el código que tenía el plugin en ese momento. Las vistas previas, las pruebas de juego y las publicaciones ejecutan ese código, aunque después publiques uno más nuevo.
- Actualizar es decisión del proyecto. Cuando hay código más nuevo, el plugin muestra update available en el panel Plugins. Update in project pasa el proyecto a esa versión.
- Tus propios proyectos siguen tus cambios. Si añadiste tu propio plugin a un proyecto, el proyecto ejecuta cada versión que guardas.
- Una publicación conserva su código. Un proyecto publicado ejecuta el código con el que se publicó, hasta que se vuelve a publicar.
Los títulos, las descripciones y las etiquetas de los disparadores, los pasos y los ajustes pueden
salir de tus archivos de idioma, escritos como
${…}.
Plugins solo para suscriptores
El código de ejecución de un plugin llega a todos los que abren el proyecto publicado, y cualquiera puede leerlo en su navegador. Esto también vale para un plugin Subscribers only. La suscripción decide quién puede añadir el plugin a un proyecto, actualizarlo y publicar con él. No oculta el código.
Si termina la suscripción, un proyecto que usa el plugin no se puede volver a publicar. Renueva la suscripción o quita el plugin. Un proyecto que ya está publicado sigue funcionando.
Para desarrolladores
- El código de ejecución se ejecuta en el worker de scripts del proyecto, junto con los scripts del proyecto.
- La versión que guarda un proyecto es una huella de los archivos de ejecución, los disparadores, los pasos y los ajustes. Si la huella cambia, aparece update available.
Siguiente: Atajos de teclado: las teclas que agilizan la edición.