Entidades y componentes
Aprende lo esencial sobre entidades y componentes en una escena de Decentraland
Las escenas de Decentraland se construyen alrededor de entities, components y systems. Este es un patrón común utilizado en la arquitectura de varios motores de juego, que permite una fácil composabilidad y escalabilidad.

Visión general
Entities son la unidad básica para construir todo en las escenas de Decentraland. Todos los objetos 3D visibles e invisibles y los reproductores de audio en tu escena serán cada uno una entity. Una entity no es más que un id, que puede ser referenciado por components. La entity en sí no tiene propiedades ni métodos propios, simplemente sirve para agrupar varios components.
Components definen los rasgos de una entity. Por ejemplo, un Transform component almacena las coordenadas, rotación y escala de la entity. Un MeshRenderer component le da a la entity una forma visible (como un cubo o una esfera) cuando se renderiza en la escena, un Material component le da a la entity un color o textura. También puedes crear components personalizados para los datos que requiera tu escena, por ejemplo un health podría almacenar el valor de salud restante de una entity, y añadirlo a entities que representen enemigos no jugadores en un juego.
Si estás familiarizado con el desarrollo web, piensa en las entities como el equivalente a Elements en un DOM tree, y en los components como attributes de esos elementos.
En el Scene Editor in Creator Hub, puedes ver los components que pertenecen a una entity seleccionándola.

📔 Nota: En versiones anteriores del SDK, las Entities eran objects que se instanciaban y podían extenderse para agregar funciones. A partir de la versión 7.0 del SDK, las entities son solo un ID. Esta estructura se ajusta mejor a los principios de data oriented programming y puede ayudar en el rendimiento de la escena.

Components como Transform, Material o cualquiera de los shape components están estrechamente ligados al renderizado de la escena. Si los valores en estos components cambian, eso por sí solo es suficiente para que el engine cambie cómo se renderiza la escena en el siguiente frame.
El engine es la parte de la escena que se sitúa en el medio y gestiona todas las demás partes. Determina qué entities se renderizan y cómo los jugadores interactúan con ellas. También coordina qué funciones de systems se ejecutan y cuándo.
Los components están destinados a almacenar datos sobre su entity referenciada. Solo pueden almacenar estos datos, no pueden modificar estos datos por sí mismos. Todos los cambios en los valores de los components son llevados a cabo por Systems. Los Systems están completamente desacoplados de los components y las entities en sí. Las entities y los components son agnósticos respecto a qué systems están actuando sobre ellos.
Sintaxis para entities y components
El ejemplo abajo muestra algunas operaciones básicas para declarar y configurar entities y components básicos.
📔 Nota: En versiones anteriores del SDK, era necesario añadir manualmente una entity al engine para comenzar a renderizarla. A partir de la versión 7 del SDK, las entities se añaden implícitamente al engine tan pronto como se les asigna un component.
Cuando se crea un component, siempre se asigna a una entity padre. Los valores del component entonces afectan a la entity.
Eliminar entities
Para eliminar una entity del engine, usa engine.removeEntity()
Si una entity eliminada tiene alguna child entities, estas cambian su parent de vuelta a la por defecto engine.RootEntity entity, que está posicionada en la posición base de la escena, con una escala de 1.
Para eliminar una entity y también todos sus children (y cualquier children de sus children, recursivamente), usa la removeEntityWithChildren() helper.
Eliminar entities detrás de escena
Una entity es solo un id que es referenciado por sus components. Así que al eliminar una entity en realidad estás eliminando cada uno de los components que referencian esa entity. Esto significa que si eliminas manualmente todos los components de una entity, tendrá el mismo efecto que hacer engine.removeEntity().
Una vez que los components de la entity son eliminados, el id de esa entity queda libre para ser referenciado por nuevos components como una entity completamente nueva.
Entities anidadas
Una entity puede tener otras entities como children. Gracias a esto, podemos organizar entities en árboles, al igual que el HTML de una página web.

Para establecer una entity como parent de otra, la entity child debe tener un Transform component. Entonces puedes establecer el campo parent con una referencia a la entity parent.
Una vez que se asigna un parent, puede leerse desde la child entity desde el campo parent en su Transform component.
Si una entity parent tiene un Transform component que afecta su posición, escala o rotación, sus child entities también se ven afectadas. Cualquier valor de posición o rotación se suma, cualquier valor de escala se multiplica.
Si ni la parent ni la child entity tienen un Transform component, se usan los siguientes valores por defecto.
Para position, el centro del parent es 0, 0, 0
Para rotation la rotación del parent es el quaternion 0, 0, 0, 1 (equivalente a los ángulos Euler 0, 0, 0)
Para scale, el parent se considera que tiene un tamaño de 1. Cualquier cambio de tamaño del parent afecta la escala y posición en proporción.
Entities sin component de shape son invisibles en la escena. Estas pueden usarse como envoltorios para manejar y posicionar múltiples entities como un grupo.
Para separar una child entity de su parent, puedes asignar el parent de la entity a engine.RootEntity.
📔 Nota: Al tratar con entities anidadas que se sincronizan con otros jugadores, usa la parentEntity() function en lugar de la parent entity en el Transform. Ver Parented entities
En el Scene Editor, puedes ver toda la jerarquía de entities anidadas en tu escena en el panel lateral izquierdo.

Obtener una entity por ID
Cada entity en tu escena tiene un número único id. Puedes recuperar un component que hace referencia a una entity específica desde el engine basado en este ID.
📔 Nota: Los ids de entity entre 0 y 511 están reservados por el engine para entities fijas, como el avatar del jugador, la escena base, etc.
Por ejemplo, si el clic de un jugador o un raycast impacta una entity, esto devolverá el id de la entity impactada, y puedes usar el comando arriba para obtener el Transform component de la entity que coincida con ese id. También puedes obtener cualquier otro component de esa entity de la misma manera.
Obtener una entity por nombre
Al añadir entities mediante arrastrar y soltar en el Scene Editor, cada entity tiene un nombre único. Usa la engine.getEntityOrNullByName() function para referenciar una de estas entities desde tu código. Pasa el nombre de la entity como una string, tal como aparece en la UI del Scene Editor, en la vista de árbol a la izquierda.
📔 Nota: Asegúrate de usar solamente engine.getEntityOrNullByName() inside the main() function, en funciones que se ejecuten después de main(), o en un system. Si se usa fuera de uno de esos contextos, las entities creadas en la UI del Scene Editor pueden no haber sido instanciadas todavía.
Eres libre de realizar cualquier acción sobre una entity obtenida por este método, como añadir o eliminar components, modificar valores de components existentes, o eliminar la entity del engine.
Todas las entities añadidas mediante la UI del Scene Editor tienen un Name component, puedes iterar sobre todas ellas así:
Añadir o reemplazar un component
Cada entity solo puede tener un component de un tipo dado. Por ejemplo, si intentas asignar un Transform a una entity que ya tiene uno, esto causará un error.
Para prevenir este error, puedes usar .createOrReplace en lugar de .create. Este comando sobrescribe cualquier component existente del mismo tipo si existe, de lo contrario crea un component nuevo igual que .create.
📔 Nota: Dado que .createOrReplace realiza una verificación adicional antes de crear el component, siempre es más eficiente usar .create. Si estás seguro de que la entity no tiene ya un component como el que estás añadiendo, usa .create.
Acceder a un component desde una entity
Puedes acceder a los components de una entity usando el .get() de la entity o las funciones getMutable() .
La get() function obtiene una referencia de solo lectura al component. No puedes cambiar ningún valor desde esta referencia del component.
Si deseas cambiar los valores del component, usa la getMutable() function en su lugar. Si cambias los valores en la versión mutable del component, estás afectando directamente a la entity a la que pertenece ese component.
Ver mutable data para más detalles.
📔 Nota: Usa únicamente getMutable() si realmente vas a hacer cambios en los valores del component. De lo contrario, siempre usa get(). Esta práctica sigue los principios de data oriented programmingy puede ayudar significativamente en el rendimiento de la escena.
El ejemplo anterior modifica directamente el valor de la x escala en el Transform component.
Si no estás totalmente seguro de si la entity tiene el component que intentas obtener, usa getOrNull() o getMutableOrNull().
📔 Nota: Evita usar getOrNull() o getMutableOrNull() cuando sea posible, ya que estas funciones implican verificaciones adicionales y por tanto son menos eficientes que .get() y getMutable().
Si el component que intentas obtener no existe en la entity:
get()ygetMutable()devuelve un error.getOrNull()ygetMutableOrNull()devuelveNull.
Eliminar un component de una entity
Para eliminar un component de una entity, usa el deleteFrom() método del tipo de component.
Si intentas eliminar un component que no existe en la entity, esta acción no generará errores.
📔 Nota: Para eliminar todos los components de una entity a la vez, consulta esta sección
Comprobar si existe un component
Puedes comprobar si una entity posee una instancia de cierto component usando la función has() . Esta función devuelve true si el component está presente, y false si no lo está. Esto puede ser muy útil para usar en la lógica condicional de tu escena.
Comprobar cambios en un component
Usa la onChange function para ejecutar una función de callback cada vez que los valores del component cambian para una entity dada. Esto funciona en cualquier component y es un gran atajo para mantener tu código legible.
La función de callback puede incluir un parámetro de entrada que contiene el nuevo estado del component.
Si el component es eliminado de la entity, entonces la función es llamada con una entrada de undefined.
📔 Nota: La .onChange() function actualmente solo funciona con components nativos del SDK, no funciona con custom comopnents definidos por el creador.
Entities reservadas
Ciertos ids de entity están reservados para entities especiales que existen en cada escena. Pueden ser accedidas mediante los siguientes alias:
engine.RootEntityengine.PlayerEntityengine.CameraEntity
📔 Nota: Evita referirte a estas entities antes de que estén inicializadas. Para evitar este problema, refiérete a estas entities en la main() function, o en un system.
La entity raíz
Todas las entities en la escena son children de la engine.RootEntity, directa o indirectamente.
Esta entity carece de un Transform component, pero se usa para manejar varios components que representan configuraciones más globales, como skybox control, cursor position, o screen dimensions.
La entity del jugador
La engine.PlayerEntity entity representa el avatar del jugador.
Obtén el Transform component del jugador para obtener la posición y rotación actuales del jugador, ver user data. El Transform del jugador es de solo lectura, para modificarlo usa la movePlayerTo() function, learn more.
También puedes adjuntar objetos al jugador configurándolos como children de esta entity, aunque el Attach to Player suele ser la mejor opción para eso.
La entity de la cámara
La engine.CameraEntity entity representa la cámara del jugador.
Obtén el Transform component de la cámara para obtener la posición y rotación de la cámara. El Transform de esta entity también es de solo lectura. Para modificar el ángulo o la posición de la cámara, usa una Virtual camera.
También puedes obtener el CameraMode component de la cámara para saber si el jugador está usando el modo de cámara en 1ª o 3ª persona, ver camera mode.
Última actualización