# Entities e Components

As cenas de Decentraland são construídas em torno de [*entities*, *components* e *systems*](https://en.wikipedia.org/wiki/Entity%E2%80%93component%E2%80%93system). Este é um padrão comum usado na arquitetura de vários engines de jogos, que permite uma fácil composability e escalabilidade.

![](/files/d62829da4dc69be10b0d3103c853468fef617c91)

## Visão geral

*Entities* são a unidade básica para construir tudo nas cenas de Decentraland. Todos os objetos 3D visíveis e invisíveis e os reprodutores de áudio na tua cena serão, cada um, uma entity. Uma entity não é mais do que um id, que pode ser referenciado por components. A própria entity não tem propriedades nem methods próprias; serve simplesmente para agrupar vários components em conjunto.

*Components* definem os atributos de uma entity. Por exemplo, um `Transform` component armazena as coordenadas, rotação e escala da entity. Um `MeshRenderer` component dá à entity uma forma visível (como um cube ou uma sphere) quando rendered na cena, um `Material` component dá à entity uma cor ou texture. Também podes criar custom components para fornecer os dados necessários à tua scene, por exemplo um custom `health` poderia armazenar o valor de saúde restante de uma entity e adicioná-lo a entities que representam inimigos não-jogadores num jogo.

Se estás familiarizado com desenvolvimento web, pensa em entities como o equivalente de *Elements* num *DOM* tree, e em components como *attributes* desses elements.

No campo [Scene Editor no Creator Hub](/creator/content-creator-pt/scene-editor/comecar/about-editor.md), podes ver os components que pertencem a uma entity selecionando-a.

![](/files/e35f285ad89a711d580efe0f6e45346c4de9e6b2)

{% hint style="warning" %}
**📔 Nota**: Em versões anteriores do SDK, as Entities eram *objects* que eram instanciados e podiam ser estendidos para adicionar functions. A partir da versão 7.0 do SDK, as entities são apenas um ID. Esta estrutura adapta-se melhor aos princípios de [data oriented programming](/creator/content-creator-pt/scenes-sdk7/arquitetura/data-oriented-programming.md) e pode ajudar no desempenho da scene.
{% endhint %}

![](/files/80e21cd981361bb7f2f7b3bcab9f02eb3539fb1c)

Components como `Transform`, `Material` ou qualquer um dos *shape* components estão intimamente ligados ao rendering da cena. Se os valores destes components mudarem, isso por si só é suficiente para que o engine altere a forma como a cena é rendered no frame seguinte.

O engine é a parte da cena que fica no meio e gere todas as outras partes. Determina que entities são rendered e como os players interagem com elas. Também coordena que functions de [systems](/creator/content-creator-pt/scenes-sdk7/arquitetura/systems.md) são executadas e quando.

Components destinam-se a armazenar dados sobre a entity referenciada. Só podem armazenar estes dados; não podem modificar estes dados por si mesmos. Todas as alterações aos valores nos components são realizadas por [Systems](/creator/content-creator-pt/scenes-sdk7/arquitetura/systems.md). Os Systems estão completamente desacoplados dos components e das entities em si. As entities e os components são agnósticos em relação a que *systems* estão a agir sobre eles.

## Sintaxe para entities e components

O exemplo abaixo mostra algumas operações básicas para declarar e configurar entities e components básicos.

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

	// Dar uma posição à entity via um component Transform
	Transform.create(door, {
		position: Vector3.create(5, 1, 5),
	})

	// Dar à entity uma forma visível via um component GltfContainer
	GltfContainer.create(door)
}
```

{% hint style="warning" %}
**📔 Nota**: Em versões anteriores do SDK, era necessário adicionar manualmente uma entity ao engine para começar a renderizá-la. A partir da versão 7 do SDK, as entities são implicitamente adicionadas ao engine assim que lhes é atribuído um component.
{% endhint %}

Quando um component é criado, é sempre atribuído a uma entity pai. Os valores do component afetam então a entity.

## Remover entities

Para remover uma entity do engine, usa `engine.removeEntity()`

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

	// Dar à entity uma forma visível via um component GltfContainer
	GltfContainer.create(door)

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

Se uma entity removida tiver alguma child entity, estas alteram o seu parent de volta para a entity predefinida `engine.RootEntity` entity, que está posicionada na base da scene, com uma scale de *1*.

Para remover uma entity e também todas as suas children (e quaisquer children das suas children, recursivamente), usa o helper `removeEntityWithChildren()` .

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

	// Criar entity filha
	const doorKnob = engine.addEntity()

	// Dar às entities uma forma visível
	GltfContainer.create(door, {
		src: 'models/door.glb',
	})
	GltfContainer.create(doorKnob, {
		src: 'models/doorKnob.glb',
	})

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

	// Remover pai e children
	removeEntityWithChildren(engine, door)
}
```

{% hint style="info" %}
**💡 Dica**: Em vez de remover uma entity do engine, nalguns casos pode ser melhor torná-la invisível, caso queiras poder carregá-la novamente sem qualquer atraso. Consulta [Tornar invisível](/creator/content-creator-pt/scenes-sdk7/essenciais-de-conteudo-3d/shape-components.md#make-invisible)
{% endhint %}

### Remover entities nos bastidores

Uma entity é apenas um id que é referenciado pelos seus components. Portanto, ao remover uma entity, estás na verdade a remover cada um dos components que referenciam esta entity. Isto significa que, se removeres manualmente todos os components de uma entity, isso terá o mesmo efeito que fazer `engine.removeEntity()`.

Depois de os components da entity serem removidos, o id dessa entity fica livre para ser referenciado por novos components como uma entity nova e fresca.

## Entities aninhadas

Uma entity pode ter outras entities como children. Graças a isso, podemos organizar entities em trees, tal como o HTML de uma página web.

![](/files/1a48e83e21cfbc5c91afbd058cb1d16d6d77b1ff)

Para definir uma entity como parent de outra, a child entity deve ter um `Transform` component. Podes então definir o campo `parent` com uma referência para a entity pai.

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

	const childEntity = engine.addEntity()

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

Uma vez atribuído um parent, ele pode ser lido na child entity a partir do campo `parent` no seu `Transform` componente.

```ts
// Obter parent de uma entity
const parent = Transform.get(childEntity).parent
```

Se uma entity pai tiver um `Transform` component que afete a sua position, scale ou rotation, as suas child entities também são afetadas. Quaisquer valores de position ou rotation são adicionados, quaisquer valores de scale são multiplicados.

Se a entity pai ou child não tiver um `Transform` component, são usados os seguintes valores predefinidos.

* Para **posição**, o centro da entity pai é *0, 0, 0*
* Para **rotação** a rotação da entity pai é o quaternion *0, 0, 0, 1* (equivalente aos ângulos de Euler *0, 0, 0*)
* Para **escala**, considera-se que a entity pai tem um tamanho de *1*. Qualquer redimensionamento da entity pai afeta a scale e a position em proporção.

Entities sem component de shape são invisíveis na cena. Estas podem ser usadas como wrappers para gerir e posicionar várias entities como um grupo.

Para separar uma child entity do seu parent, podes atribuir o parent da entity a `engine.RootEntity`.

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

{% hint style="warning" %}
**📔 Nota**: Ao trabalhar com entities aninhadas sincronizadas com outros players, usa o `parentEntity()` função em vez de `parent` entity no Transform. Consulta [Entities parented](/creator/content-creator-pt/scenes-sdk7/networking/serverless-multiplayer.md#parented-entities)
{% endhint %}

No Scene Editor, podes ver a hierarquia completa de entities aninhadas na tua cena no painel do lado esquerdo.

![](/files/8e683951551eceee811b3359f57c72ba4ea24737)

## Obter uma entity por ID

Cada entity na tua cena tem um número único *id*. Podes recuperar um component que se refere a uma entity específica do engine com base neste ID.

```typescript
// obter um component Transform
Transform.get(1000 as Entity)
```

{% hint style="warning" %}
**📔 Nota**: Os ids das entities entre *0* e *511* são reservados pelo engine para entidades fixas, como o avatar do player, a base da scene, etc.
{% endhint %}

Por exemplo, se um clique do player ou um [raycast](/creator/content-creator-pt/scenes-sdk7/interatividade/raycasting.md) atingir uma entity, isto devolverá o id da entity atingida, e podes usar o comando acima para obter o component Transform da entity que corresponde a esse id. Também podes obter qualquer outro component dessa entity da mesma forma.

## Obter uma entity por nome

Ao adicionar entities via drag-and-drop no Scene Editor, cada entity tem um nome único. Usa a `engine.getEntityOrNullByName()` function para referenciar uma dessas entities a partir do teu código. Passa o nome da entity como uma string, tal como está escrito na UI do Scene Editor, na árvore à esquerda.

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

{% hint style="warning" %}
**📔 Nota**: Certifique-se de usar `engine.getEntityOrNullByName()` apenas dentro da `main()` função, em funções que executam após `main()`, ou num system. Se usado fora de um desses contextos, as entities criadas na UI do Scene Editor podem ainda não estar instanciadas.
{% endhint %}

És livre de realizar qualquer ação numa entity obtida através deste método, como adicionar ou remover components, modificar valores de components existentes ou remover a entity do engine.

```ts
function main() {
	// obter entity
	const door = engine.getEntityOrNullByName('door-3')
	// verificar se a entity existe
	if (door) {
		// adicionar um callback de pointer events
		pointerEventsSystem.onPointerDown(
			{
				entity: door,
				opts: { button: InputAction.IA_PRIMARY, hoverText: 'Open' },
			},
			function () {
				// abrir porta
			}
		)
	}
}
```

Todas as entities adicionadas via a UI do Scene Editor têm um `Nome` component, podes iterar por todas elas assim:

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

## Adicionar ou substituir um component

Cada entity só pode ter um component de um dado tipo. Por exemplo, se tentares atribuir um Transform a uma entity que já tenha um, isso causará um erro.

Para evitar este erro, podes usar `.createOrReplace` em vez da `.create`. Este comando substitui quaisquer components existentes do mesmo tipo, se existirem; caso contrário, cria um novo component tal como `.create`.

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

{% hint style="warning" %}
**📔 Nota**: Como `.createOrReplace` executa uma verificação adicional antes de criar o component, é sempre mais performante usar `.create`. Se tens a certeza de que a entity ainda não tem um component como o que estás a adicionar, usa `.create`.
{% endhint %}

## Aceder a um component a partir de uma entity

Podes aceder aos components de uma entity usando os `.get()` ou o `getMutable()` functions da entity.

```ts
export function main() {
	// Criar entity
	const box = engine.addEntity()

	// Criar e adicionar component a essa entity
	Transform.create(box)

	// Obter versão só de leitura do component
	let transform = Transform.get(box)

	// Obter versão mutável do component
	let transform = Transform.getMutable(box)
}
```

O `get()` function obtém uma referência só de leitura para o component. Não podes alterar quaisquer valores a partir desta referência do component.

Se quiseres alterar os valores do component, usa a `getMutable()` function em vez disso. Se alterares os valores na versão mutável do component, estás a afetar diretamente a entity à qual esse component pertence.

Veja [dados mutáveis](/creator/content-creator-pt/scenes-sdk7/padroes-de-programacao/mutable-data.md) para mais detalhes.

{% hint style="warning" %}
**📔 Nota**: Usa apenas `getMutable()` se fores realmente fazer alterações aos valores do component. Caso contrário, usa sempre `get()`. Esta prática segue os princípios de [data oriented programming](/creator/content-creator-pt/scenes-sdk7/arquitetura/data-oriented-programming.md), e pode ajudar significativamente no desempenho da scene.
{% endhint %}

```ts
// Obter versão mutável do component
let transform = Transform.getMutable(box)

// alterar um valor do component
transform.scale.x = 5
```

O exemplo acima modifica diretamente o valor de *x* a scale no component Transform.

Se não tens a certeza absoluta de que a entity tem o component que estás a tentar obter, usa `getOrNull()` ou `getMutableOrNull()`.

{% hint style="warning" %}
**📔 Nota**: Evita usar `getOrNull()` ou `getMutableOrNull()` sempre que possível, já que estas functions envolvem verificações adicionais e são, por isso, menos eficientes do que `.get()` e `getMutable()`.
{% endhint %}

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

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

Se o component que estás a tentar obter não existir na entity:

* `get()` e `getMutable()` devolve um erro.
* `getOrNull()` e `getMutableOrNull()` devolve `Null`.

## Remover um component de uma entity

Para remover um component de uma entity, usa o `deleteFrom()` method do tipo de component.

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

Se tentares remover um component que não existe na entity, esta ação não irá gerar quaisquer erros.

{% hint style="warning" %}
**📔 Nota**: Para remover todos os components de uma entity de uma só vez, consulta [esta secção](#remove-entities)
{% endhint %}

## Verificar a existência de um component

Podes verificar se uma entity possui uma instância de um certo component usando a `has()` function. Esta function devolve *true* se o component estiver presente, e *false* se não estiver. Isto pode ser muito útil para usar em lógica condicional na tua scene.

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

{% hint style="info" %}
**💡 Dica**: Também podes [consultar components](/creator/content-creator-pt/scenes-sdk7/arquitetura/querying-components.md) para obter uma lista completa de components que contenham um component específico, ou um conjunto específico de components. Não iteres manualmente por todas as entities na cena para verificar cada uma com um `has()`, essa abordagem é muito menos eficiente.
{% endhint %}

## Verificar alterações num component

Use a `onChange` function para executar uma callback function sempre que os valores do component mudarem para uma determinada entity. Isto funciona em qualquer component e é um ótimo atalho para ajudar a manter o teu código legível.

A callback function pode incluir um parâmetro de input que contém o novo state do component.

```ts
Transform.onChange(cubeEntity, (newTransform) => {
	if (!newTransform) return
	console.log(
		'A position do cubo mudou: ',
		newTransform.position,
		newTransform.rotation
	)
})

VisibilityComponent.onChange(cubeEntity, (newVisibilityComponent) => {
	if (!newVisibilityComponent) return
	console.log('A visibilidade do cubo mudou: ', newVisibilityComponent.visible)
})
```

Se o component for removido da entity, então a function é chamada com uma entrada de `undefined`.

{% hint style="warning" %}
**📔 Nota**: O `.onChange()` function atualmente só funciona com native components do SDK; não funciona com [custom comopnents](/creator/content-creator-pt/scenes-sdk7/arquitetura/custom-components.md) definidos pelo criador.
{% endhint %}

## Obter todas as entities descendentes

Ao trabalhar com hierarquias de entities aninhadas, podes precisar de aceder a todas as entities que são descendentes de uma entity pai, independentemente de quão profundamente aninhadas estejam. Para isso podes usar `getEntitiesWithParent`. Toma como argumentos a `engine` como as `parent` entity e devolve uma lista de todas as entities que têm essa Entiy específica como parent.

Isto é especialmente útil quando precisas de encontrar entities que podem estar aninhadas sob vários níveis abaixo de uma entity pai. Em vez de percorrer manualmente a hierarquia nível a nível, `getEntitiesWithParent()` devolve uma lista plana de todos os descendants, fácil de iterar.

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

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

Poderás, em alternativa, querer usar a function `getComponentEntityTree()`, que também filtra apenas entities que tenham um dado component ou uma lista de components.

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

export function main() {
	// Criar uma entity pai com children aninhadas
	const parentEntity = engine.addEntity()
	Transform.create(parentEntity, {
		position: Vector3.create(8, 0, 8),
	})

	// ... assume que a entity pai tem várias children e grandchildren

	// Iterar por todos os descendants da entity pai
	for (const descendantEntity of getComponentEntityTree(
		engine,
		parentEntity,
		Transform
	)) {
		// Aceder a cada entity descendant
		const transform = Transform.get(descendantEntity)
		console.log('Position do descendant:', transform.position)
	}
}
```

O `getComponentEntityTree` function recebe três parâmetros:

* `engine`: A instância do engine que está a executar as entities
* `entity`: A entity raiz a partir da qual começar
* `component`: O component pelo qual filtrar (normalmente `Transform` para hierarquias espaciais)

A function devolve um generator que produz cada entity descendant na estrutura em tree. Apenas as entities que tenham o component especificado serão incluídas nos resultados.

Podes combinar isto com outras verificações de components para encontrar entities específicas na tua hierarquia:

```ts
// Encontrar todos os descendants com um nome específico
for (const descendantEntity of getComponentEntityTree(
	engine,
	parentEntity,
	Transform
)) {
	const name = Name.getOrNull(descendantEntity)
	if (name && name.value === 'targetEntity') {
		console.log('Entity alvo encontrada:', descendantEntity)
	}
}
```

## Entities reservadas

Certos ids de entity são reservados para entidades especiais que existem em todas as scenes. Podem ser acedidos através dos seguintes aliases:

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

{% hint style="warning" %}
**📔 Nota**: Evita referir-te a estas entities antes de serem inicializadas. Para evitar este problema, refere-te a estas entities na `main()` function, ou num system.
{% endhint %}

## A entity raiz

Todas as entities na cena são children da `engine.RootEntity`, direta ou indiretamente.

Esta entity não tem um component Transform, mas é usada para gerir vários components que representam definições mais globais, como [controlo do skybox](/creator/content-creator-pt/scenes-sdk7/interatividade/skybox-control.md), [posição do cursor](/creator/content-creator-pt/scenes-sdk7/interatividade/user-data.md#check-the-players-cursor-position), ou [dimensões do ecrã](/creator/content-creator-pt/scenes-sdk7/ui-2d/ui-positioning.md#responsive-ui-size).

## A entity do player

O `engine.PlayerEntity` entity representa o avatar do player.

Obtém o `Transform` component do player para obter a position e rotation atuais do player, consulta [dados do user](/creator/content-creator-pt/scenes-sdk7/interatividade/user-data.md). O Transform do player é só de leitura; para o modificar, usa a `movePlayerTo()` function, [sabe mais](/creator/content-creator-pt/scenes-sdk7/interatividade/player-avatar.md#move-player).

Também podes anexar objects ao player, definindo-os como children desta entity, embora o [Attach to Player](/creator/content-creator-pt/scenes-sdk7/essenciais-de-conteudo-3d/entity-positioning.md#attach-an-entity-to-an-avatar) seja muitas vezes a melhor option para isso.

## A entity da camera

O `engine.CameraEntity` entity representa a camera do player.

Obtém o `Transform` component da camera para obter a position e rotation da camera. O Transform desta entity também é só de leitura. Para modificar o ângulo ou a position da camera, usa uma [Virtual camera](/creator/content-creator-pt/scenes-sdk7/essenciais-de-conteudo-3d/camera.md#using-virtual-cameras).

Também podes obter o `CameraMode` component da camera para saber se o player está a usar o modo de camera em 1.ª ou 3.ª pessoa, consulta [modo de camera](/creator/content-creator-pt/scenes-sdk7/interatividade/user-data.md#check-the-players-camera-mode).


---

# Agent Instructions: 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:

```
GET https://docs.decentraland.org/creator/content-creator-pt/scenes-sdk7/arquitetura/entities-components.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
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.
