Fundamentos de codificación

Este conjunto te ayudará a entender cómo funcionan las cosas en el cliente y el SDK de Decentraland.

Las herramientas de desarrollo

A muy alto nivel, el Decentraland Software Development Kit (SDK) te permite hacer lo siguiente:

  • Generar un proyecto que contenga una escena de Decentraland, incluyendo todos los assets necesarios para renderizar y ejecutar tu contenido.

  • Construir, probar y previsualizar el contenido de tu escena localmente en tu navegador web - completamente sin conexión, y sin necesidad de realizar transacciones en Ethereum ni de poseer LAND.

  • Escribir código en TypeScript usando la API de Decentraland para añadir comportamiento interactivo y dinámico a la escena.

  • Subir el contenido de tu escena al servidor de contenido.

  • Vincular tus tokens LAND a la URL del contenido que has subido.

Nuestro SDK incluye lo siguiente:

  • The Creator Hub: Una aplicación independiente que, entre otras cosas, te permite crear escenas con una interfaz sencilla de arrastrar y soltar. Puedes ejecutar previsualizaciones, depurar, editar código y publicar. Leer más

  • The Decentraland ECS: Un paquete de TypeScript que contiene el framework de métodos auxiliares que te permite crear experiencias interactivas. Úsalo para crear y manipular objetos en la escena y también para facilitar transacciones dentro del mundo entre jugadores u otras aplicaciones. ( última referencia de ECSarrow-up-right)

  • Ejemplos de escenas: Toma inspiración y mejores prácticas de codificación de los ejemplos de escenaarrow-up-right.

Otras herramientas heredadas:

  • The Web Editor: Una herramienta basada en la web para crear escenas simples y publicarlas.

Requisitos

Para desarrollar una escena localmente, no necesitas poseer tokens LAND. Desarrollar y probar una escena puede hacerse completamente sin conexión, sin la necesidad de desplegar una escena en la red Ethereum (el sistema que Decentraland usa para establecer la propiedad de LAND, de un Decentraland Name), ni en el servidor de contenido.

Debes tener:

  • The Creator Hub: Una aplicación independiente que, entre otras cosas, te permite crear escenas con una interfaz sencilla de arrastrar y soltar. Puedes ejecutar previsualizaciones, depurar, editar código y publicar. Leer más.

Si planeas editar el código de la escena, también necesitarás instalar una de las siguientes:

  • VS Code Visual Studio Code: Descárgalo aquíarrow-up-right. Te ayuda a escribir código mucho más rápido y con menos errores. Un editor de código fuente marca errores de sintaxis, autocompleta mientras escribes e incluso te muestra sugerencias inteligentes que dependen del contexto en el que te encuentras. También puedes hacer clic en un objeto en el código para ver la definición completa de su clase y qué atributos soporta.

  • Cursor Cursor AI: Descárgalo aquíarrow-up-right. Un potente editor de código integrado con IA. Te permite elegir diferentes modelos de IA para ayudarte a escribir código, todos ellos son gratuitos. El asistente de IA no solo autocompleta mientras escribes, también puedes pedirle que refactorice una gran base de código, escriba documentación y más.

Idiomas y sintaxis soportados

Decentraland emplea TypeScript (.ts)arrow-up-right como el lenguaje predeterminado para escribir escenas.

TypeScript es un superconjunto de JavaScript, así que si estás familiarizado con JavaScript verás que es casi igual, pero TypeScript incluye declaraciones de tipos. Gracias a las declaraciones de tipos, es posible tener características como autocompletado y mejores pistas de depuración; estas aceleran los tiempos de desarrollo y permiten la creación de una base de código más sólida. Estas características son componentes clave para una experiencia positiva del desarrollador.

Cuando se construye una escena, el código TypeScript que escribiste se compila en Javascript minificado, para hacerlo más ligero. El código fuente original en TypeScript nunca se sube a los servidores, solo la versión compilada en Javascript.

Otros lenguajes

Puedes usar otra herramienta o lenguaje en lugar de TypeScript y compilarlo a JavaScript, siempre que tus scripts compilados estén contenidos en un único archivo JavaScript llamado game.js. Todas las declaraciones de tipos proporcionadas están hechas en TypeScript, y otros lenguajes y transpilers no cuentan con soporte oficial.

Escenas

El contenido que despliegas en tu LAND se llama un escena. Una escena es un programa interactivo que renderiza contenido 3D, esto podría ser un juego, una experiencia interactiva, una galería de arte, ¡lo que quieras!

Las escenas se despliegan en LAND virtual en Decentraland. LAND es un activo escaso y no fungible mantenido en un smart contract de Ethereum. Despliega a un solo parcel, una parcela de LAND de 16 metros por 16 metros, o a múltiples parcelas adyacentes.

Cuando los jugadores visitan Decentraland, descargan y renderizan el contenido de cada escena a medida que caminan por el mapa. Descargan las escenas cuando se alejan de ellas.

También puedes ejecutar una escena localmente en tu máquina ejecutando una previsualización desde la CLI.

Entidades y Componentes

Las escenas tridimensionales en Decentraland se basan en una Entity-Component-Systemarrow-up-right arquitectura, donde todo en una escena es una entity. Las entidades tienen components, cada componente le da a la entidad a la que pertenece propiedades específicas. Una entidad puerta probablemente tendrá al menos un componente Transform (que establece posición, rotación y escala) y otro para proporcionarle una forma. Los componentes son solo un lugar para almacenar datos, no ejecutan acciones por sí mismos.

Las entidades pueden estar anidadas dentro de otras entidades para formar una estructura de árbol. Si estás familiarizado con el desarrollo web, puede resultarte útil pensar en las entidades como elementos en un árbol DOM y en los componentes como los atributos de cada uno de estos elementos.

Las entidades son un concepto abstracto. Una entidad es solo un id, que se usa como referencia para agrupar diferentes componentes.

Vea Entidades y componentes para una mirada en profundidad de ambos conceptos y cómo los usan las escenas de Decentraland.

Componentes personalizados

El conjunto predeterminado de componentes (como Transform, GltfContainer, Material, etc.) son interpretados por el engine y tienen consecuencias directas en cómo se verá la entidad, su posición, si emite sonidos, etc.

También puedes definir componentes personalizados para almacenar datos que podrían ser útiles para las mecánicas en tu escena. El engine no sabrá cómo interpretar lo que significan los valores en estos componentes, no tendrán consecuencias directas en cómo se renderiza la escena. Sin embargo, puedes escribir lógica en el código de tu escena para monitorear estos valores y responder a ellos. Por ejemplo, puedes definir un componente personalizado "doorState" para rastrear el estado abierto/cerrado de la puerta. En este caso, el componente no es más que un lugar para almacenar un valor que mantiene el seguimiento de este estado. Para ver la puerta abrirse y cerrarse en tu escena, debes implementar por separado la lógica que use estos valores para afectar la rotación de la puerta, un valor del Transform componente que el engine sí sabe interpretar.

Vea Componentes Personalizados para más información.

Obtener entidades por nombre

Las entidades añadidas mediante arrastrar y soltar en el Scene Editor dentro de Creator Hub también pueden ser accesadas vía código para editarlas más y añadir comportamiento.

Usa engine.getEntityOrNullByName() para obtener una entidad, pasando el nombre asignado a la entidad en la UI del Scene Editor. Cada una debería tener un nombre único.

Luego puedes hacer cualquier cosa que quieras con esa entidad, como añadir nuevos componentes, modificar sus componentes existentes, duplicarla o eliminarla.

Vea Obtener entidad por nombre para más información.

Si la entidad es una Smart item, también puedes llamar a su Actions o suscribirte a sus Triggers vía código. Ver Elementos de Referencia.

Systems

Entidades y componentes son lugares para almacenar información sobre los objetos en una escena. Systems mantienen funciones que cambian la información que se almacena en los componentes a lo largo del tiempo.

Los systems son donde implementamos la lógica del juego, ejecutan las acciones que necesitan ser actualizadas o comprobadas periódicamente en cada tick del bucle del juego.

Un system es una función pura y simple que se llama una vez en cada tick (hasta 30 veces por segundo), siguiendo el patrón de actualizaciónarrow-up-right.

Una sola escena puede tener 0 o muchos systems ejecutándose al mismo tiempo. Los systems pueden activarse o desactivarse en diferentes momentos durante la duración de la escena. Generalmente es una buena práctica mantener comportamientos independientes en systems separados.

Vea Systems para más detalles sobre cómo se usan los systems en una escena.

El game loop

El bucle del juegoarrow-up-right es la columna vertebral del código de una escena de Decentraland. Cicla parte del código a intervalos regulares y hace lo siguiente:

  • Escuchar la entrada del jugador

  • Actualizar la escena

  • Volver a renderizar la escena

En la mayoría de los programas de software tradicionales, todos los eventos son desencadenados directamente por acciones del jugador. Nada en el estado del programa cambiará hasta que el jugador haga clic en un botón, abra un menú, etc.

Pero los entornos interactivos y los juegos son diferentes. No todos los cambios en la escena son necesariamente causados por las acciones de un jugador. Tu escena podría tener objetos animados que se muevan por sí mismos o incluso personajes no jugables que tengan su propia IA. Algunas acciones del jugador también pueden tardar varios ticks en completarse, por ejemplo si la apertura de una puerta necesita durar un segundo entero, la rotación de la puerta debe actualizarse incrementalmente unas 30 veces mientras se mueve.

Llamamos a cada iteración sobre el bucle un tick. Las escenas de Decentraland se renderizan a 30 ticks por segundo, cuando es posible. Si la máquina tiene dificultades para renderizar cada tick, puede resultar en actualizaciones menos frecuentes.

En cada tick, la escena se actualiza; luego la escena se vuelve a renderizar, basándose en los valores actualizados.

En las escenas de Decentraland, no existe un game loop declarado explícitamente, sino que más bien los Systems de la escena constituyen el game loop.

La compilación y el renderizado de la escena se llevan a cabo en el backend, no necesitas encargarte de eso mientras desarrollas tu escena.

Consulta de componentes

Puedes consultar componentes con el método engine.getEntitiesWith(...components) para llevar un seguimiento de todas las entidades en la escena que tienen ciertos componentes.

A menudo tiene sentido consultar componentes dentro de una system, para luego iterar sobre cada una de las entidades devueltas y realizar el mismo conjunto de acciones en cada una.

Si intentas iterar sobre todas las entidades en la escena en cada tick del game loop, eso podría tener un coste significativo en rendimiento. Al referirte solo a las entidades devueltas por una consulta, te aseguras de tratar únicamente con las que son relevantes.

Ciclo de vida de la escena

Si comienzas a escribir líneas sueltas de código directamente en index.ts, tu código puede carecer de algún contexto importante. Por ejemplo, te faltará información sobre la entidad jugador, o sobre entidades que se añadieron mediante arrastrar y soltar en Creator Hub. En el momento en que se leen tus líneas de código, esas cosas aún no están cargadas.

Para evitar ese escenario, siempre se recomienda escribir el código de carga inicial de tu escena usando la main() function (en el index.ts archivo) como punto de entrada. Esta función se ejecuta solo después de que todo el contexto inicial de la escena ya esté cargado, esto incluye cualquier cosa añadida mediante la UI del Scene Editor.

Puedes escribir tu código fuera de la main() function cuando:

  • El código es llamado indirectamente por main()

  • El código define un system, o añade un system al engine

  • El código está dentro de un async function

circle-exclamation

Mutabilidad

Puedes elegir trabajar con versiones mutables o con versiones inmutables (solo lectura) de un componente. La .get() function en un componente devuelve una versión inmutable del componente. Solo puedes leer sus valores, pero no puedes cambiar ninguna de sus propiedades.

El .getMutable() function devuelve una representación del componente que te permite cambiar sus valores. Usa versiones mutables solo cuando planees hacer cambios en un componente. Trabajar con versiones inmutables de componentes resulta en una gran ganancia de rendimiento.

Vea datos mutables para más detalles.

Poniéndolo todo junto

El engine es lo que se sitúa entre entities, y components por un lado y systems por otro.

Todos los valores almacenados en los componentes de la escena representan el estado de la escena en ese momento. Con cada tick del game loop, el engine ejecuta las funciones de cada uno de los systems para actualizar los valores almacenados en los componentes.

Después de que todos los systems se ejecuten, los componentes de cada entidad tendrán nuevos valores. Cuando el engine renderiza la escena, usará estos nuevos valores actualizados y los jugadores verán las entidades cambiar para coincidir con sus nuevos estados.

En el ejemplo anterior, una cube entidad y un rotationSystem system son añadidos al engine. La cube entidad tiene un Transform, y un MeshRenderer componente. En cada tick del game loop, el rotationSystem system es llamado, y cambia los valores de rotación en el Transform componente de la cube entidad.

Ten en cuenta que la mayor parte del código anterior se ejecuta solo una vez, al cargar la escena. La excepción es el rotationSystem system, que se llama en cada tick del game loop.

Desacoplamiento de la escena

Tus escenas no se ejecutan en el mismo contexto que el engine (también conocido como el hilo principal). Creamos el SDK de una manera que está totalmente desacoplada del motor de renderizado. Lo diseñamos así por razones de seguridad y rendimiento.

Debido a este desacoplamiento, el código de tu escena no tiene acceso al DOM ni al window objeto, por lo que no puedes acceder a datos como el navegador del jugador o la ubicación geográfica.

El desacoplamiento funciona usando el protocolo RPC, este protocolo asigna una pequeña parte del cliente solo para renderizar la escena y controlar eventos.

También hemos abstraído el protocolo de comunicación. Esto nos permite ejecutar las escenas localmente en un WebWorker.

No queremos que los desarrolladores intervengan en los internos del engine ni siquiera que necesiten saber qué hay dentro del engine. Necesitamos asegurar una experiencia consistente para los jugadores en todo el mapa de Decentraland, y es más probable que ocurran errores a ese nivel "bajo".

Este desacoplamiento también es importante para evitar que escenas vecinas interfieran con la experiencia de los jugadores mientras están en la escena de otra persona. Un jugador podría tener múltiples escenas cercanas cargadas al mismo tiempo, cada una ejecutando su propio código. Algunas acciones (como abrir enlaces externos o mover al jugador) solo están permitidas cuando el jugador está parado en esa escena en particular, no si la escena está cargada pero el jugador está fuera.

Tree Shaking

Al convertir el código fuente en TypeScript al código compilado en JavaScript minificado, el proceso realiza tree shakingarrow-up-right para asegurar que solo las partes del código que realmente se están usando sean convertidas. Esto ayuda a mantener el código final de la escena lo más ligero posible. Es especialmente útil al usar librerías externas, ya que a menudo estas librerías incluyen mucha funcionalidad que no se usa y que de otro modo inflaría la escena.

Como consecuencia del tree shaking, cualquier código que quieras que tu escena ejecute necesita ser referenciado de una manera u otra por los puntos de entrada de tu código: la main() function en index.ts. Los systems también pueden, alternativamente, añadirse al engine en el index.ts archivo, sin referenciar main(). Cualquier código que no esté explícita o indirectamente referenciado por estos archivos, no formará parte de la escena.

Por ejemplo, supongamos que tienes un archivo llamado extraContent.ts con el siguiente contenido, la entidad no se renderizará y el system no empezará a ejecutarse:

Para hacer que se ejecute como parte de tu escena, puedes referenciarlo desde index.ts de la siguiente manera:

La excepción a esta regla son las definiciones de componentes personalizados. Estos no deben ser accedidos vía el punto de entrada de la main() function, ya que necesitan ser interpretados antes que todo lo demás.

Imports

Todas las funciones, objetos, components y otros elementos usados por la escena deben importarse en cada archivo para poder usarlos. Esto es una consecuencia del tree-shaking, ya que evita empaquetar todo el SDK e incluye solamente las partes que la escena utiliza.

Los snippets a lo largo de la documentación omiten las líneas de import al inicio de cada archivo para mantenerlos limpios, pero para que funcionen debes añadirlas a la escena.

Cuando uses VS Studio Code para escribir tus escenas, las opciones inteligentes de autocompletado deberían encargarse de manejar las importaciones por ti mientras escribes, sin que tengas que ser consciente de ello.

Sin embargo, cuando pegues un snippet en tu escena, probablemente verás algunos elementos marcados en rojo, que no están importados en ese archivo. Para arreglar esto:

  • Haz clic en cada palabra subrayada

  • Haz clic en el icono de bombilla a la izquierda de la línea

  • Selecciona Añadir importación desde

  • Aparece una línea de import al inicio del archivo.

Si hay muchas cosas diferentes para importar, también puedes seleccionar Añadir todas las importaciones faltantes desde el mismo menú desplegable.

Ten en cuenta que las importaciones deben hacerse en cada archivo donde se utilice un elemento.

VS Studio Code debería ser capaz de resolver las rutas correctas a tus importaciones por sí solo. Si por alguna razón tiene problemas para hacerlo, un truco es pegar las siguientes declaraciones de import vacías al inicio de tu archivo. VS Studio debería poder encargarse desde ahí.

Versiones del SDK

Al desarrollar una nueva escena, usas la @latest versión estable del SDK por defecto.

Puedes instalar la @next versión del SDK si quieres aprovechar o previsualizar funciones próximas que aún no han llegado a la última versión estable.

Para hacerlo, abre el package.json archivo de tu escena, y cambia las siguientes líneas:

Luego ejecuta el siguiente comando en la carpeta del proyecto de tu escena:

Vea administrar dependencias para más detalles.

circle-exclamation

Última actualización