Entities y Components

Aprende lo esencial sobre entities y components en una escena de Decentraland

Las escenas de Decentraland se construyen alrededor de entities, components y systemsarrow-up-right. 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 contener los datos que requiera tu escena, por ejemplo un custom health podría almacenar el valor de vida restante de una entity, y añadirlo a las entities que representan 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 Hubarrow-up-right, puedes ver los components que pertenecen a una entity seleccionándola.


circle-exclamation


Components como Transform, Material o cualquiera de los shape components están estrechamente vinculados con el 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 systemsarrow-up-right se ejecutan y cuándo.

Los components están pensados para almacenar datos sobre su entity referenciada. Solo pueden almacenar estos datos; no pueden modificar esos datos por sí mismos. Todos los cambios en los valores de los components son realizados por Systemsarrow-up-right. Los Systems están completamente desacoplados de los components y las entities. Las entities y los components son agnósticos respecto a qué systems están actuando sobre ellos.

Sintaxis para entities y components

El ejemplo siguiente muestra algunas operaciones básicas para declarar y configurar entities y components básicos.

circle-exclamation

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 entities hijas, estas cambian su padre de nuevo a la entity por defecto engine.RootEntity , 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 hijos (y cualquier hijo de sus hijos, recursivamente), usa el removeEntityWithChildren() helper.

circle-info

💡 Consejo: En lugar de eliminar una entity del engine, en algunos casos puede ser mejor hacerla invisible, en caso de que quieras poder cargarla de nuevo sin demora. Ver Make invisiblearrow-up-right

Eliminando entities detrás de las escenas

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 se eliminan los components de la entity, 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 hijas. Gracias a esto, podemos organizar entities en árboles, igual que el HTML de una página web.



Para establecer una entity como padre de otra, la entity hija debe tener un Transform component. Entonces puedes establecer el campo parent con una referencia a la entity padre.

Una vez que se asigna un padre, puede leerse desde la entity hija a través del campo parent en su Transform component.

Si una entity padre tiene un Transform component que afecta su posición, escala o rotación, sus entities hijas también se ven afectadas. Cualquier valor de posición o rotación se suma, cualquier valor de escala se multiplica.

Si ni la entity padre ni la hija tienen un Transform component, se usan los siguientes valores predeterminados.

  • Para position, el centro del padre es 0, 0, 0

  • Para rotation la rotación del padre es el quaternion 0, 0, 0, 1 (equivalente a los ángulos de Euler 0, 0, 0)

  • Para scale, el padre se considera que tiene un tamaño de 1. Cualquier cambio de tamaño del padre afecta la escala y la posición en proporción.

Las entities sin component de shape son invisibles en la escena. Estas se pueden usar como contenedores para manejar y posicionar múltiples entities como un grupo.

Para separar una entity hija de su padre, puedes asignar el padre de la entity a engine.RootEntity.

circle-exclamation

En el Scene Editor, puedes ver toda la jerarquía de entities anidadas de tu escena en el panel izquierdo.



Obtener una entity por ID

Cada entity en tu escena tiene un número único id. Puedes recuperar un component que refiere a una entity específica desde el engine basándote en este ID.

circle-exclamation

Por ejemplo, si el clic de un jugador o un raycastarrow-up-right golpea una entity, esto devolverá el id de la entity impactada, y puedes usar el comando anterior para obtener el Transform component de la entity que coincide 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 función engine.getEntityOrNullByName() para referenciar una de estas entities desde tu código. Pasa el nombre de la entity como una cadena, tal como aparece en la UI del Scene Editor, en la vista de árbol a la izquierda.

circle-exclamation

Puedes realizar cualquier acción en una entity obtenida mediante 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 vía 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 provocará un error.

Para evitar 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 nuevo component igual que .create.

circle-exclamation

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 función get() 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 función getMutable() 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 dataarrow-up-right para más detalles.

circle-exclamation

El ejemplo anterior modifica directamente el valor de la x escala en el Transform component.

Si no estás completamente seguro de si la entity tiene el component que intentas obtener, usa getOrNull() o getMutableOrNull().

circle-exclamation

Si el component que intentas obtener no existe en la entity:

  • get() y getMutable() devuelve un error.

  • getOrNull() y getMutableOrNull() devuelve Null.

Eliminar un component de una entity

Para eliminar un component de una entity, usa el método deleteFrom() del tipo de component.

Si intentas eliminar un component que no existe en la entity, esta acción no lanzará ningún error.

circle-exclamation

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.

circle-info

💡 Consejo: También puedes query componentsarrow-up-right para obtener una lista completa de entities que poseen un component específico, o un conjunto específico de components. No itures sobre todas las entities en la escena manualmente para comprobar cada una con un has(), ese enfoque es mucho menos eficiente.

Comprobar cambios en un component

Usa la función onChange para ejecutar una función callback cada vez que los valores del component cambien para una entity dada. Esto funciona en cualquier component y es un gran atajo para mantener tu código legible.

La función callback puede incluir un parámetro de entrada que contiene el nuevo estado del component.

Si el component se elimina de la entity, entonces la función es llamada con una entrada de undefined.

circle-exclamation

Obtener todas las entities descendientes

Al trabajar con jerarquías de entities anidadas, puede que necesites acceder a todas las entities que son descendientes de una entity padre, sin importar cuán profundamente anidadas estén. Para eso puedes usar getEntitiesWithParent. Toma como argumentos el engine y la parent entity y devuelve una lista de todas las entities que tienen esa Entiy en particular como su padre.

Esto es especialmente útil cuando necesitas encontrar entities que pueden estar anidadas bajo varios niveles bajo una entity padre. En lugar de recorrer manualmente la jerarquía nivel por nivel, getEntitiesWithParent() devuelve una lista plana de todos los descendientes que es fácil de iterar.

Si lo deseas, también puedes usar la función getComponentEntityTree(), que también filtra solo las entities que tienen un component dado o una lista de components.

La función getComponentEntityTree function toma tres parámetros:

  • engine: La instancia del engine que ejecuta las entities

  • entity: La entity raíz desde la que empezar

  • component: El component por el que filtrar (típicamente Transform para jerarquías espaciales)

La función devuelve un generador que produce cada entity descendiente en la estructura del árbol. Solo se incluirán en los resultados las entities que tengan el component especificado.

Puedes combinar esto con otras comprobaciones de components para encontrar entities específicas en tu jerarquía:

Entities reservadas

Ciertos ids de entity están reservados para entities especiales que existen en cada escena. Se pueden acceder mediante los siguientes alias:

  • engine.RootEntity

  • engine.PlayerEntity

  • engine.CameraEntity

circle-exclamation

La entity raíz

Todas las entities de la escena son hijas 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 controlarrow-up-right, cursor positionarrow-up-right, o screen dimensionsarrow-up-right.

La entity del jugador

La función 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 dataarrow-up-right. El Transform del jugador es de solo lectura; para modificarlo usa la función movePlayerTo() , más informaciónarrow-up-right.

También puedes adjuntar objetos al jugador estableciéndolos como hijos de esta entity, aunque la opción Attach to Playerarrow-up-right suele ser la mejor opción para eso.

La entity de la cámara

La función 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 cameraarrow-up-right.

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 modearrow-up-right.

Última actualización