Primer script
Escribe un pequeño script que hace girar un objeto cuando lo tocas. Después, añade ajustes al inspector y descubre qué puede usar un script.
Un script es un archivo de TypeScript que añades a un objeto. Se ejecuta en el reproductor. Cada objeto que usa el script tiene su propia copia.
Este es un script completo. Toca el objeto y empieza a girar:
import { TransformComponent } from '@was/engine';
init((ctx) => {
const props = defineProps({
speed: { type: 'number', default: 1, min: 0, label: 'Speed' },
});
let spinning = false;
ctx.on('on-click', () => {
spinning = !spinning;
});
ctx.tick((dt) => {
if (!spinning) return;
const t = ctx.entity.getComponent(TransformComponent);
t?.update({
rotation: { ...t.$data.rotation, y: t.$data.rotation.y + props.speed * dt },
});
});
return () => {
// opcional: limpia lo necesario cuando este objeto desaparece
};
});
El script tiene cuatro partes:
| Parte | Qué hace |
|---|---|
init | Arranca el script y te da ctx, tu acceso a la escena en marcha. Todo empieza aquí. |
defineProps | Añade ajustes al inspector. Los rellenas en cada objeto. |
ctx.on | Reacciona a un disparador, como un toque o una colisión. |
ctx.tick | Se ejecuta en cada fotograma. dt es el tiempo desde el fotograma anterior, en segundos. |
init y defineProps están siempre disponibles. Nunca tienes que importarlos. Las clases de
componente, como TransformComponent, vienen de @was/engine.
Lee y cambia objetos
const transform = ctx.entity.getComponent(TransformComponent);
transform.position; // lee un valor
transform.$data; // lee todo como un objeto simple
transform.update({ … }); // escribe
Hay dos errores en los que cae casi todo el mundo.
update conserva los campos que no pasas, como rotation. Pero un valor que pasas sustituye
entero al anterior. Así que update({ position: { y: 2 } }) también devuelve x y z a su valor
por defecto, cero.
Copia con ... los valores que quieras conservar:
transform.update({ position: { ...transform.$data.position, y: 2 } });
material.update({ color }) no hace nada, porque color está dentro de un slot. Cambia el slot:
material.update({
materials: [{ ...material.$data.materials[0], color: '#ff0000' }],
});
Nunca cambies $data directamente. Parece que funciona, pero el cambio se pierde.
Ajustes en el inspector
Con defineProps, puedes poner un mismo script en diez objetos y configurarlo de forma distinta
en cada uno. Sin copiar y pegar.
const props = defineProps({
speed: { type: 'number', default: 1, min: 0, softMax: 10, suffix: 'm/s' },
target: { type: 'entity', label: 'Look at' },
sound: { type: 'resource', resource: 'audio' },
mode: { type: 'select', options: ['chase', 'patrol'], default: 'patrol' },
});
| Tipo | El editor muestra | Tu script recibe |
|---|---|---|
number | un campo o un deslizador | un número |
string | un campo de texto | una cadena |
boolean | un interruptor | un booleano |
color | un selector de color | una cadena con el color |
select | un desplegable | una de tus opciones |
entity | un selector de objetos | el propio objeto, listo para usar |
scene | un selector de escenas | el objeto de la escena |
resource | un selector de recursos | una referencia que puedes pasar a otras funciones |
array | una lista | un array |
group | un bloque con título | un objeto anidado |
Opciones útiles:
labelyhelp: el texto que se muestra en el panel.minymax: límites estrictos.softMax: dónde termina el deslizador. Se puede seguir escribiendo un número mayor.showWhen: muestra un campo solo cuando otro campo tiene un valor concreto.group: mantiene ordenada una lista larga de ajustes.
defineProps completoEscribe tus ajustes directamente dentro de la llamada, o el inspector no podrá mostrarlos. No los construyas a partir de variables ni los devuelvas desde una función.
Tu script siempre recibe el valor actual: props.speed vale lo que muestre el inspector en ese
momento.
Importaciones
import { TransformComponent } from '@was/engine';
import helpers from 'Scripts/helpers';
Puedes importar las clases de componente del motor. También puedes importar otros recursos por su ruta:
- otro script te da lo que exporta;
- un patch te da su código, el mismo que muestra el panel Code;
- cualquier otra cosa te da una referencia,
{ id, type }. Pásala actx.spawn, o pasa suidactx.audio.play.
Si cambias el nombre de un recurso o lo mueves, estas importaciones se actualizan solas.
Lo que un script no puede usar
Un script pesado no puede ralentizar la imagen. En los scripts no están disponibles:
window,document, el DOM;fetch,localStorageni ningún acceso a la red;- las bibliotecas de renderizado: cambias la escena a través de los componentes, no dibujando;
- los temporizadores del navegador: usa
ctx.tick.
En su lugar, usa esto:
- para la interfaz, tarjetas de interfaz;
- para el sonido,
ctx.audio; - para guardar valores,
ctx.storey las variables globales.
Cuándo empieza y termina un script
Un script empieza cuando su objeto está activo en pantalla: no hay nada desactivado por encima de él y su escena está activa. Termina cuando eso deja de cumplirse.
on-launch se dispara en cuanto el script empieza, así que nunca te lo pierdes.
La función que devuelves desde init se ejecuta cuando el script termina. Úsala para limpiar:
cancelar suscripciones, parar sonidos, borrar el estado.
El editor muestra tu escena, pero no ejecuta ninguna lógica. Edita el script y abre la vista previa (Preview). No hay recarga en caliente: una experiencia en marcha recoge tus cambios la próxima vez que se reinicia.
Siguiente: Dónde van los scripts: en qué nivel añadir un script.