> For the complete documentation index, see [llms.txt](https://docs.decentraland.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.decentraland.org/creator/content-creator-es/escenas-sdk7/arquitectura/entities-components.md).

# Entities y Components

Las escenas de Decentraland se construyen en torno a [*entities*, *components* y *systems*](https://en.wikipedia.org/wiki/Entity%E2%80%93component%E2%80%93system). Este es un patrón común usado en la arquitectura de varios motores de juego, que permite una fácil componibilidad y escalabilidad.

![](/files/f8ae24ca96098f4c403470a24f18af76952e3f4c)

## Resumen

*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 un entity cada uno. Un entity no es más que un id, que puede ser referenciado por components. El entity en sí no tiene propiedades ni métodos propios, simplemente sirve para agrupar varios components juntos.

*Components* definen las características de un entity. Por ejemplo, un `Transform` component almacena las coordenadas, rotación y escala del entity. Un `MeshRenderer` component le da al entity una forma visible (como un cubo o una esfera) cuando se renderiza en la escena; un `Material` component le da al entity un color o una textura. También puedes crear components personalizados para servir a los datos requeridos por tu escena; por ejemplo, un custom `health` podría almacenar el valor de salud restante de un entity y añadirlo a entities que representen enemigos que no sean jugadores en un juego.

Si estás familiarizado con el desarrollo web, piensa en entities como el equivalente de *Elementos* en un *DOM* árbol, y de components como *atributos* de esos elementos.

En el [Scene Editor en Creator Hub](/creator/content-creator-es/scene-editor/empezar/about-editor.md), puedes ver los components que pertenecen a un entity seleccionándolo.

![](/files/b2afe33441f5a6afaa286b52bb8ae870ba7920f0)

{% hint style="warning" %}
**📔 Nota**: En versiones anteriores del SDK, Entities eran *objetos* que se instanciaban y podían extenderse para añadir funciones. A partir de la versión 7.0 del SDK, entities son solo un ID. Esta estructura se ajusta mejor a los principios de [programación orientada a datos](/creator/content-creator-es/escenas-sdk7/arquitectura/data-oriented-programming.md) y puede ayudar en el rendimiento de la escena.
{% endhint %}

![](/files/7d4643619a2a6fc20c713c2e197e5cf44ad37e6b)

Components como `Transform`, `Material` o cualquiera de los *shape* components están estrechamente ligados al renderizado de la escena. Si los valores de estos components cambian, eso por sí solo basta 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 centro y gestiona todas las demás partes. Determina qué entities se renderizan y cómo interactúan los jugadores con ellos. También coordina qué functions de [systems](/creator/content-creator-es/escenas-sdk7/arquitectura/systems.md) se ejecutan y cuándo.

Los Components están destinados a almacenar datos sobre el entity al que hacen referencia. Solo pueden almacenar estos datos; no pueden modificarlos por sí mismos. Todos los cambios en los valores de los components son realizados por [Systems](/creator/content-creator-es/escenas-sdk7/arquitectura/systems.md). Los Systems están completamente desacoplados de los components y de los entities en sí. Entities y components son agnósticos respecto a qué *systems* systems actúan sobre ellos.

## Sintaxis para entities y components

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

```ts
export function main() {
	// Crear un entity
	const door = engine.addEntity()

	// Darle al entity una posición mediante un component Transform
	Transform.create(door, {
		position: Vector3.create(5, 1, 5),
	})

	// Darle al entity una forma visible mediante un component GltfContainer
	GltfContainer.create(door, {
		src: 'assets/models/door.glb',
	})
}
```

{% hint style="warning" %}
**📔 Nota**: En versiones anteriores del SDK, era necesario añadir manualmente un entity al engine para comenzar a renderizarlo. A partir de la versión 7 del SDK, los entities se añaden implícitamente al engine en cuanto se les asigna un component.
{% endhint %}

Cuando se crea un component, siempre se asigna a un entity padre. Los valores del component entonces afectan al entity.

{% hint style="info" %}
**💡 Consejo**: En lugar de crear entities uno por uno, puedes generar de una vez un árbol completo de entities y components a partir de un [composite](/creator/content-creator-es/escenas-sdk7/arquitectura/composites.md) archivo.
{% endhint %}

## Eliminar entities

Para eliminar un entity del engine, usa `engine.removeEntity()`

```ts
export function main() {
	// Crear un entity
	const door = engine.addEntity()

	// Darle al entity una forma visible mediante un component GltfContainer
	GltfContainer.create(door, {
		src: 'assets/models/door.glb',
	})

	// Eliminar entity
	engine.removeEntity(door)
}
```

Si un entity eliminado tiene algún entity hijo, estos cambian su padre de vuelta al `engine.RootEntity` entity predeterminado, que está posicionado en la posición base de la escena, con una escala de *1*.

Para eliminar un entity y también todos sus hijos (y cualquier hijo de sus hijos, recursivamente), usa el `removeEntityWithChildren()` helper.

```ts
export function main() {
	// Crear entity padre
	const door = engine.addEntity()

	// Crear entity hijo
	const doorKnob = engine.addEntity()

	// Dar a los entities una forma visible
	GltfContainer.create(door, {
		src: 'models/door.glb',
	})
	GltfContainer.create(doorKnob, {
		src: 'models/doorKnob.glb',
	})

	// Padre
	Transform.create(doorKnob, {
		parent: door,
	})

	// Eliminar tanto al padre como a los hijos
	removeEntityWithChildren(engine, door)
}
```

{% hint style="info" %}
**💡 Consejo**: En lugar de eliminar un entity del engine, en algunos casos puede ser mejor hacerlo invisible, por si quieres poder cargarlo de nuevo sin ningún retraso. Ver [Hacer invisible](/creator/content-creator-es/escenas-sdk7/conceptos-basicos-de-contenido-3d/shape-components.md#make-invisible)
{% endhint %}

### Eliminar entities en segundo plano

Un entity no es más que un id al que hacen referencia sus components. Así que, al eliminar un entity, en realidad estás eliminando cada uno de los components que hacen referencia a ese entity. Si eliminas manualmente todos los components de un entity, se verá igual para el jugador que hacer `engine.removeEntity()`. Sin embargo, `engine.removeEntity()` también realiza algunos controles internos adicionales, marcando el id del entity como ya no en uso, así que siempre es la forma recomendada de eliminar un entity.

## Entities anidados

Un entity puede tener otros entities como hijos. Gracias a ello, podemos organizar entities en árboles, igual que el HTML de una página web.

![](/files/99f33f4e5e6c6645fd06dbf9fadb49f4d281ba70)

Para establecer un entity como padre de otro, el entity hijo debe tener un `Transform` component. Entonces puedes establecer el `parent` field con una referencia al entity padre.

```ts
export function main() {
	// Crear entities
	const parentEntity = engine.addEntity()

	const childEntity = engine.addEntity()

	// Establecer padre
	Transform.create(childEntity, {
		parent: parentEntity,
	})
}
```

Una vez asignado un padre, se puede leer en el entity hijo desde el `parent` field en su `Transform` componente.

```ts
// Obtener el padre desde un entity
const parent = Transform.get(childEntity).parent
```

Si un entity padre tiene un `Transform` component que afecta a 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 el entity padre o el entity hijo no tiene un `Transform` component, se usan los siguientes valores predeterminados.

* Para **posición**, el centro del padre es *0, 0, 0*
* Para **rotación** la rotación del padre es el quaternion *0, 0, 0, 1* (equivalente a los ángulos de Euler *0, 0, 0*)
* Para **escala**, el padre se considera que tiene un tamaño de *1*. Cualquier redimensionamiento del padre afecta a la escala y la posición en proporción.

Los entities sin component shape son invisibles en la escena. Pueden usarse como contenedores para gestionar y posicionar varios entities como un grupo.

Para separar un entity hijo de su padre, puedes asignar el padre del entity a `engine.RootEntity`.

```ts
const mutableChildTransform = Transform.getMutable(childEntity)
mutableChildTransform.parent = engine.RootEntity
```

{% hint style="warning" %}
**📔 Nota**: Al trabajar con entities anidados que están sincronizados con otros jugadores, usa el `parentEntity()` función en lugar de la `parent` entity en el Transform. Ver [Entidades con parent](/creator/content-creator-es/escenas-sdk7/redes/serverless-multiplayer.md#parented-entities)
{% endhint %}

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

![](/files/30278ba2ad960770f1a3acb204c9c852974969e5)

## Obtener un entity por ID

Cada entity en tu escena tiene un número único *id*. Puedes recuperar del engine un component que hace referencia a un entity específico basándote en este ID.

```typescript
// obtener un component Transform
Transform.get(1000 as Entity)
```

{% hint style="warning" %}
**📔 Nota**: Los ids de entity entre *0* y *511* están reservados por el engine para entities fijos, como el avatar del jugador, la escena base, etc.
{% endhint %}

Por ejemplo, si el click de un jugador o un [raycast](/creator/content-creator-es/escenas-sdk7/interactividad/raycasting.md) impacta con un entity, esto devolverá el id del entity impactado, y puedes usar el comando anterior para obtener el component Transform del entity que coincide con ese id. También puedes obtener cualquier otro component de ese entity de la misma manera.

## Obtener un entity por nombre

Al añadir entities mediante drag-and-drop en el Scene Editor, cada entity tiene un nombre único. Usa la `engine.getEntityOrNullByName()` función para referenciar uno de estos entities desde tu código. Pasa el nombre del entity como una string, tal como está escrito en la UI del Scene Editor, en la vista de árbol de la izquierda.

```ts
function main() {
	const door = engine.getEntityOrNullByName('door3')
}
```

{% hint style="warning" %}
**📔 Nota**: Asegúrate de usar solo la `engine.getEntityOrNullByName()` dentro de la `main()` función, en funciones que se ejecutan después de `main()`, o en un system. Si se usa fuera de uno de esos contextos, es posible que los entities creados en la UI del Scene Editor aún no estén instanciados.
{% endhint %}

Eres libre de realizar cualquier acción sobre un entity obtenido mediante este método, como añadir o eliminar components, modificar valores de components existentes o eliminar el entity del engine.

```ts
function main() {
	// obtener entity
	const door = engine.getEntityOrNullByName('door-3')
	// verificar que el entity existe
	if (door) {
		// añadir una callback de PointerEvents
		pointerEventsSystem.onPointerDown(
			{
				entity: door,
				opts: { button: InputAction.IA_PRIMARY, hoverText: 'Open' },
			},
			function () {
				// abrir la puerta
			}
		)
	}
}
```

Todos los entities añadidos mediante la UI del Scene Editor tienen un `Name` component, puedes iterar sobre todos ellos así:

```ts
function main() {
	for (const [entity, name] of engine.getEntitiesWith(Name)) {
		console.log({ entity, name })
	}
}
```

## 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 un 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`.

```ts
Transform.createOrReplace(door, {
	position: Vector3.create(5, 1, 5),
})
```

{% hint style="warning" %}
**📔 Nota**: Como `.createOrReplace` realiza una comprobación adicional antes de crear el component, siempre es más eficiente usar `.create`. Si estás seguro de que el entity no tiene ya un component como el que estás añadiendo, usa `.create`.
{% endhint %}

## Acceder a un component desde un entity

Puedes acceder a los components de un entity usando el `.get()` sin código `getMutable()` funciones.

```ts
export function main() {
	// Crear Entity
	const box = engine.addEntity()

	// Crear y añadir un component a ese entity
	Transform.create(box)

	// Obtener la versión de solo lectura del component
	let transform = Transform.get(box)

	// Obtener la versión mutable del component
	let transform = Transform.getMutable(box)
}
```

El `get()` función 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()` función en su lugar. Si cambias los valores en la versión mutable del component, estás afectando directamente al entity al que pertenece ese component.

Consulta [mutable data](/creator/content-creator-es/escenas-sdk7/patrones-de-programacion/mutable-data.md) para ver más detalles.

{% hint style="warning" %}
**📔 Nota**: Usa solo la `getMutable()` si realmente vas a realizar cambios en los valores del component. De lo contrario, usa siempre la `get()`. Esta práctica sigue los principios de [programación orientada a datos](/creator/content-creator-es/escenas-sdk7/arquitectura/data-oriented-programming.md)y puede ayudar significativamente al rendimiento de la escena.
{% endhint %}

```ts
// Obtener la versión mutable del component
let transform = Transform.getMutable(box)

// cambiar un valor del component
transform.scale.x = 5
```

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

Si no estás del todo seguro de que el entity tenga el component que estás intentando recuperar, usa `getOrNull()` o `getMutableOrNull()`.

{% hint style="warning" %}
**📔 Nota**: Evita usar `getOrNull()` o `getMutableOrNull()` cuando sea posible, ya que estas functions implican comprobaciones adicionales y, por tanto, son menos eficientes que `.get()` y `getMutable()`.
{% endhint %}

```ts
//  getOrNull
const transformOrNull = Transform.getOrNull(myEntity)

//  getMutableOrNull
const mutableTransformOrNull = Transform.getMutableOrNull(myEntity)
```

Si el component que intentas recuperar no existe en el entity:

* `get()` y `getMutable()` devuelve un error.
* `getOrNull()` y `getMutableOrNull()` devuelve `Null`.

## Eliminar un component de un entity

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

```ts
Transform.deleteFrom(myEntity)
```

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

{% hint style="warning" %}
**📔 Nota**: Para eliminar todos los components de un entity de una vez, consulta [esta sección](#remove-entities)
{% endhint %}

## Comprobar si existe un component

Puedes comprobar si un entity posee una instancia de un determinado component usando la `has()` función. Esta función devuelve *true* true si el component está presente, y *false* false si no lo está. Esto puede ser muy útil para usarlo en lógica condicional en tu escena.

```ts
const hasTransform = Transform.has(myEntity)
```

{% hint style="info" %}
**💡 Consejo**: También puedes [consultar components](/creator/content-creator-es/escenas-sdk7/arquitectura/querying-components.md) para obtener una lista completa de entities que tienen un component específico, o un conjunto específico de components. No iters manualmente sobre todos los entities de la escena para comprobar cada uno con un `has()`, ese enfoque es mucho menos eficiente.
{% endhint %}

## Comprobar cambios en un component

Usa la `onChange` función para ejecutar una callback cada vez que los valores del component cambien para un entity determinado. Funciona con cualquier component, y es un gran atajo para ayudar a que tu código siga siendo legible.

La callback puede incluir un parámetro de entrada que contenga el nuevo estado del component.

```ts
Transform.onChange(cubeEntity, (newTransform) => {
	if (!newTransform) return
	console.log(
		'La posición del Cube ha cambiado: ',
		newTransform.position,
		newTransform.rotation
	)
})

VisibilityComponent.onChange(cubeEntity, (newVisibilityComponent) => {
	if (!newVisibilityComponent) return
	console.log('La visibilidad del Cube ha cambiado: ', newVisibilityComponent.visible)
})
```

Si el component se elimina del entity, entonces la función se llama con un input de `undefined`.

{% hint style="info" %}
**💡 Consejo**: La `.onChange()` función funciona tanto con components nativos del SDK como con [custom components](/creator/content-creator-es/escenas-sdk7/arquitectura/custom-components.md) definidos por el creador.
{% endhint %}

## Obtener entities hijas

Para acceder a todos los entities que son hijos directos de un entity padre, usa `getEntitiesWithParent`. Toma como argumentos el `engine` y la `parent` entity y devuelve una lista de todos los entities que tienen ese entity concreto como padre. Ten en cuenta que solo devuelve hijos directos, no hijos de hijos.

```ts
import { getEntitiesWithParent } from '@dcl/sdk/ecs'

const children = getEntitiesWithParent(engine, myEntity)
for (const child of children) {
   // procesar cada entity hijo
}
```

Para acceder en cambio a todos los descendientes de un entity, sin importar lo profundamente anidados que estén, usa la función `getComponentEntityTree()`. En lugar de recorrer manualmente la jerarquía nivel por nivel, esta función devuelve una lista plana de todos los descendientes fácil de iterar. También filtra solo los entities que tienen un component dado o una lista de components.

```ts
import { getComponentEntityTree } from '@dcl/sdk/ecs'

export function main() {
	// Crear un entity padre con hijos anidados
	const parentEntity = engine.addEntity()
	Transform.create(parentEntity, {
		position: Vector3.create(8, 0, 8),
	})

	// ... asume que el padre tiene varios hijos y nietos

	// Iterar sobre todos los descendientes del entity padre
	for (const descendantEntity of getComponentEntityTree(
		engine,
		parentEntity,
		Transform
	)) {
		// Acceder a cada entity descendiente
		const transform = Transform.get(descendantEntity)
		console.log('Posición del descendiente:', transform.position)
	}
}
```

El `getComponentEntityTree` function toma tres parámetros:

* `engine`: La instancia del engine que ejecuta los entities
* `entity`: El entity raíz desde el que empezar
* `componente`: El component por el que filtrar (normalmente `Transform` para jerarquías espaciales)

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

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

```ts
// Encontrar todos los descendientes con un nombre específico
for (const descendantEntity of getComponentEntityTree(
	engine,
	parentEntity,
	Transform
)) {
	const name = Name.getOrNull(descendantEntity)
	if (name && name.value === 'targetEntity') {
		console.log('Se encontró el entity objetivo:', descendantEntity)
	}
}
```

## Entidades reservadas

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

* `engine.RootEntity`
* `engine.PlayerEntity`
* `engine.CameraEntity`

{% hint style="warning" %}
**📔 Nota**: Evita referirte a estos entities antes de que se inicialicen. Para evitar este problema, refiérete a estos entities en la `main()` función, o en un system.
{% endhint %}

## El root entity

Todos los entities de la escena son hijos del `engine.RootEntity`, directamente o indirectamente.

Este entity no tiene un component Transform, pero se usa para gestionar varios components que representan ajustes más globales, como [el control del skybox](/creator/content-creator-es/escenas-sdk7/interactividad/skybox-control.md), [la posición del cursor](/creator/content-creator-es/escenas-sdk7/interactividad/user-data.md#check-the-players-cursor-position), o [las dimensiones de la pantalla](/creator/content-creator-es/escenas-sdk7/ui-2d/ui-positioning.md#responsive-ui-size).

## El player entity

El `engine.PlayerEntity` entity representa el avatar del jugador.

Obtén el `Transform` component para obtener la posición y rotación actuales del jugador; consulta [datos de usuario](/creator/content-creator-es/escenas-sdk7/interactividad/user-data.md). El Transform del jugador es de solo lectura; para modificarlo usa la `movePlayerTo()` función, [saber más](/creator/content-creator-es/escenas-sdk7/interactividad/player-avatar.md#move-player).

También puedes adjuntar objetos al jugador estableciéndolos como hijos de este entity, aunque la [Attach to Player](/creator/content-creator-es/escenas-sdk7/conceptos-basicos-de-contenido-3d/entity-positioning.md#attach-an-entity-to-an-avatar) suele ser la mejor opción para eso.

## El camera entity

El `engine.CameraEntity` entity representa la cámara del jugador.

Obtén el `Transform` component para obtener la posición y rotación de la cámara. El Transform de este entity también es de solo lectura. Para modificar el ángulo o la posición de la cámara, usa una [Cámara virtual](/creator/content-creator-es/escenas-sdk7/conceptos-basicos-de-contenido-3d/camera.md#using-virtual-cameras).

También puedes obtener el `CameraMode` component para saber si el jugador está usando el modo de cámara en primera o tercera persona; consulta [modo de cámara](/creator/content-creator-es/escenas-sdk7/interactividad/user-data.md#check-the-players-camera-mode).


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.decentraland.org/creator/content-creator-es/escenas-sdk7/arquitectura/entities-components.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
