# Entities & Components

As cenas da 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 diversos motores de jogo, que permite fácil composibilidade e escalabilidade.

![](https://2402076176-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoPnXBby9S6MrsW83Y9qZ%2Fuploads%2Fgit-blob-de62a18d51b28bebd55c86e8ef5a8a783467ae62%2Fecs-big-picture.png?alt=media)

## Visão geral

*Entities* são a unidade básica para construir tudo nas cenas da Decentraland. Todos os objetos 3D visíveis e invisíveis e reprodutores de áudio na sua cena serão cada um uma entity. Uma entity nada mais é do que um id, que pode ser referenciado por components. A própria entity não possui propriedades ou métodos próprios, serve simplesmente para agrupar vários components.

*Components* definem as características 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 cubo ou uma esfera) quando renderizada na cena, um `Material` component dá à entity uma cor ou textura. Você também pode criar components personalizados para armazenar os dados necessários da sua cena, por exemplo um custom `health` poderia armazenar o valor de vida restante de uma entity, e adicioná-lo a entities que representam inimigos não-jogadores em um jogo.

Se você está familiarizado com desenvolvimento web, pense em entities como o equivalente a *Elements* em uma *DOM* tree, e em components como *attributes* dessas elements.

No [Scene Editor in Creator Hub](https://github.com/decentraland/docs/blob/main/creator/sdk7/scene-editor/get-started/about-editor.md), você pode ver os components que pertencem a uma entity selecionando-a.

![](https://2402076176-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoPnXBby9S6MrsW83Y9qZ%2Fuploads%2Fgit-blob-2ffe3126d7a92824658497ed2664fcfcc28ce16a%2Fcomponents-example.png?alt=media)

{% hint style="warning" %}
**📔 Nota**: Em versões anteriores do SDK, Entities eram *objects* que eram instanciados e podiam ser estendidos para adicionar funções. A partir da versão 7.0 do SDK, entities são apenas um ID. Essa estrutura se ajusta melhor aos princípios da [data oriented programming](https://github.com/decentraland/docs/blob/main/creator/sdk7/sdk7/architecture/data-oriented-programming.md) e pode ajudar no desempenho da cena.
{% endhint %}

![](https://2402076176-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoPnXBby9S6MrsW83Y9qZ%2Fuploads%2Fgit-blob-ee29a02358e859a30079072e8da958b899aea659%2Fecs-components-new.png?alt=media)

Components como `Transform`, `Material` ou qualquer um dos *shape* components estão intimamente ligados à renderização da cena. Se os valores nesses components mudam, isso por si só é suficiente para o engine alterar como a cena é renderizada no próximo frame.

O engine é a parte da cena que fica no meio e gerencia todas as outras partes. Ele determina quais entities são renderizadas e como os players interagem com elas. Também coordena quais funções de [systems](https://github.com/decentraland/docs/blob/main/creator/sdk7/sdk7/architecture/systems.md) são executadas e quando.

Components destinam-se a armazenar dados sobre a entity referenciada. Eles só podem armazenar esses dados, não podem modificar esses dados por si mesmos. Todas as alterações nos valores dos components são realizadas por [Systems](https://github.com/decentraland/docs/blob/main/creator/sdk7/sdk7/architecture/systems.md). Systems são completamente desacoplados dos components e das entities em si. Entities e components são agnósticos quanto ao que *systems* está atuando 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() {
	// Crie uma entity
	const door = engine.addEntity()

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

	// Dê à entity uma forma visível via um GltfContainer component
	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, entities são implicitamente adicionadas ao engine assim que lhes é atribuído um component.
{% endhint %}

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

## Remover entities

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

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

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

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

Se uma entity removida tiver quaisquer entities filhas, estas mudam seu pai de volta para a `engine.RootEntity` entity, que está posicionada na posição base da cena, com uma escala de *1*.

Para remover uma entity e também todos os seus filhos (e quaisquer filhos dos seus filhos, recursivamente), use o `removeEntityWithChildren()` helper.

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

	// Crie uma entity filha
	const doorKnob = engine.addEntity()

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

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

	// Remover tanto o pai quanto os filhos
	removeEntityWithChildren(engine, door)
}
```

{% hint style="info" %}
**💡 Dica**: Em vez de remover uma entity do engine, em alguns casos pode ser melhor torná-la invisível, caso você queira ser capaz de carregá-la novamente sem qualquer atraso. Veja [Make invisible](https://github.com/decentraland/docs/blob/main/creator/sdk7/sdk7/3d-essentials/shape-components.md#make-invisible)
{% endhint %}

### Removendo entities nos bastidores

Uma entity é apenas um id que é referenciado por seus components. Então, ao remover uma entity você na verdade está removendo cada um dos components que referenciam essa entity. Isso significa que se você remover manualmente todos os components de uma entity, isso terá o mesmo efeito que fazer `engine.removeEntity()`.

Uma vez que os components da entity são removidos, o id dessa entity fica livre para ser referenciado por novos components como uma nova entity.

## Entities aninhadas

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

![](https://2402076176-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoPnXBby9S6MrsW83Y9qZ%2Fuploads%2Fgit-blob-8b6c8cd679f648a41400eb6f29889cd09ede8947%2Fecs-nested-entities-new.png?alt=media)

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

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

	const childEntity = engine.addEntity()

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

Uma vez que um pai é atribuído, ele pode ser lido a partir da entity filha pelo `parent` campo no seu `Transform` component.

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

Se uma entity pai tiver um `Transform` component que afeta sua posição, escala ou rotação, suas entities filhas também são afetadas. Qualquer valor de posição ou rotação é somado, quaisquer valores de escala são multiplicados.

Se tanto a entity pai quanto a filha não tiverem um `Transform` component, os seguintes valores padrão são usados.

* Para **position**, o centro do pai é *0, 0, 0*
* Para **rotation** a rotação do pai é o quaternion *0, 0, 0, 1* (equivalente aos ângulos Euler *0, 0, 0*)
* Para **scale**, o pai é considerado ter um tamanho de *1*. Qualquer redimensionamento do pai afeta escala e posição proporcionalmente.

Entities sem component de shape são invisíveis na cena. Estas podem ser usadas como recipientes para manipular e posicionar múltiplas entities como um grupo.

Para separar uma entity filha de seu pai, você pode atribuir o pai da entity para `engine.RootEntity`.

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

{% hint style="warning" %}
**📔 Nota**: Ao lidar com entities aninhadas que são sincronizadas com outros players, use a `parentEntity()` função em vez da `parent` entity no Transform. Veja [Parented entities](https://github.com/decentraland/docs/blob/main/creator/sdk7/sdk7/networking/serverless-multiplayer.md#parented-entities)
{% endhint %}

No Scene Editor, você pode ver toda a hierarquia de entities aninhadas na sua cena no painel lateral esquerdo.

![](https://2402076176-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoPnXBby9S6MrsW83Y9qZ%2Fuploads%2Fgit-blob-60929069a225f48ce0d6c94d9dce285ff875af10%2Fentity-tree-example.png?alt=media)

## Obter uma entity por ID

Cada entity na sua cena tem um número único *id*. Você pode recuperar um component que se refere a uma entity específica do engine com base nesse ID.

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

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

Por exemplo, se o clique de um player ou um [raycast](https://github.com/decentraland/docs/blob/main/creator/sdk7/sdk7/interactivity/raycasting.md) atinge uma entity, isso retornará o id da entity atingida, e você pode usar o comando acima para buscar o Transform component da entity que corresponde àquele id. Você também pode buscar qualquer outro component dessa entity da mesma forma.

## Obter uma entity por nome

Ao adicionar entities via arrastar-e-soltar no Scene Editor, cada entity tem um nome único. Use a `engine.getEntityOrNullByName()` função para referenciar uma dessas entities a partir do seu código. Passe o nome da entity como uma string, conforme escrito na UI do Scene Editor, na visualização em á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 rodem após `main()`, ou em um system. Se usado fora de um desses contextos, as entities criadas na UI do Scene Editor podem ainda não estar instanciadas.
{% endhint %}

Você pode realizar qualquer ação em uma entity buscada via este método, como adicionar ou remover components, modificar valores de components existentes ou remover a entity do engine.

```ts
function main() {
	// buscar 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 `Name` component, você pode iterar sobre 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 pode ter apenas um component de um determinado tipo. Por exemplo, se você tentar atribuir um Transform a uma entity que já tem um, isso causará um erro.

Para evitar esse erro, você pode usar `.createOrReplace` em vez de `.create`. Este comando sobrescreve quaisquer components existentes do mesmo tipo se existirem, caso contrário cria um novo component assim como `.create`.

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

{% hint style="warning" %}
**📔 Nota**: Como `.createOrReplace` executa uma checagem adicional antes de criar o component, é sempre mais performático usar `.create`. Se você tem certeza de que a entity não possui já um component como o que você está adicionando, use `.create`.
{% endhint %}

## Acessar um component a partir de uma entity

Você pode acessar os components de uma entity usando o `.get()` da entity `ou as funções` getMutable()

```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) `A` get()

função busca uma referência apenas de leitura ao component. Você não pode alterar quaisquer valores a partir dessa referência do component. `ou as funções` Se você deseja alterar os valores do component, use a função

em vez disso. Se você alterar os valores na versão mutável do component, você estará afetando diretamente a entity à qual esse component pertence. [Veja](https://github.com/decentraland/docs/blob/main/creator/sdk7/sdk7/programming-patterns/mutable-data.md) mutable data

{% hint style="warning" %}
**📔 Nota**para mais detalhes. `ou as funções` : Use `A`apenas se você realmente for fazer alterações nos valores do component. Caso contrário, sempre use [data oriented programming](https://github.com/decentraland/docs/blob/main/creator/sdk7/sdk7/architecture/data-oriented-programming.md). Esta prática segue os princípios de
{% endhint %}

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

, e pode ajudar significativamente no desempenho da cena.
// alterar um valor do component
```

transform.scale.x = 5 *O exemplo acima modifica diretamente o valor da* x

scale no component Transform. `Se você não tem certeza se a entity realmente possui o component que você está tentando recuperar, use` getOrNull() `ou`.

{% hint style="warning" %}
**📔 Nota**getMutableOrNull() `Se você não tem certeza se a entity realmente possui o component que você está tentando recuperar, use` getOrNull() `ou` : Evite usar `.get()` e `ou as funções`.
{% endhint %}

```ts
quando possível, pois essas funções envolvem checagens adicionais e são portanto menos eficientes que
//  getOrNull

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

const mutableTransformOrNull = Transform.getMutableOrNull(myEntity)

* `A` e `ou as funções` Se o component que você está tentando recuperar não existir na entity:
* `Se você não tem certeza se a entity realmente possui o component que você está tentando recuperar, use` e `ou` retorna um erro. `retorna`.

## Null

Remover um component de uma entity `Para remover um component de uma entity, use o` deleteFrom()

```ts
método do tipo de component.
```

Transform.deleteFrom(myEntity)

{% hint style="warning" %}
**📔 Nota**Se você tentar remover um component que não existe na entity, essa ação não gerará erros. [: Para remover todos os components de uma entity de uma vez, veja](#remove-entities)
{% endhint %}

## esta seção

Verificar um component `Você pode verificar se uma entity possui uma instância de certo component usando a função` has() *. Esta função retorna* true *se o component estiver presente, e* false

```ts
se não estiver. Isso pode ser muito útil para usar em lógica condicional na sua cena.
```

{% hint style="info" %}
**💡 Dica**const hasTransform = Transform.has(myEntity) [: Você também pode](https://github.com/decentraland/docs/blob/main/creator/sdk7/sdk7/architecture/querying-components.md) query components `Você pode verificar se uma entity possui uma instância de certo component usando a função`para buscar uma lista completa de entities que possuem um component específico, ou um conjunto específico de components. Não itere manualmente por todas as entities na cena para verificar cada uma com um
{% endhint %}

## , essa abordagem é muito menos eficiente.

Verificar mudanças em um component `Use a função` onChange

para executar uma função de callback sempre que os valores do component mudarem para uma dada entity. Isso funciona em qualquer component, e é um ótimo atalho para manter seu código legível.

```ts
A função de callback pode incluir um parâmetro de entrada que contém o novo estado do component.
	Transform.onChange(cubeEntity, (newTransform) => {
	if (!newTransform) return
		console.log(
		'Cube position changed: ',
		newTransform.position,
	)
})

newTransform.rotation
	VisibilityComponent.onChange(cubeEntity, (newVisibilityComponent) => {
	if (!newVisibilityComponent) return
})
```

console.log('Cube visibility changed: ', newVisibilityComponent.visible) `Se o component for removido da entity, então a função é chamada com uma entrada de`.

{% hint style="warning" %}
**📔 Nota**undefined `: A função` .onChange() [atualmente só funciona com components nativos do SDK, não funciona com](https://github.com/decentraland/docs/blob/main/creator/sdk7/sdk7/architecture/custom-components.md) custom comopnents
{% endhint %}

## definidos pelo criador.

Obter todas as entities descendentes `Ao trabalhar com hierarquias de entities aninhadas, você pode precisar acessar todas as entities que são descendentes de uma entity pai, independentemente de quão profundamente aninhadas estejam. Para isso você pode usar`getEntitiesWithParent `. Ela recebe como argumentos o` engine `parent` e a

entity e retorna uma lista de todas as entities que têm aquela entidade específica como seu pai. `Isso é especialmente útil quando você precisa 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 por nível,` getEntitiesWithParent()

```ts
retorna uma lista plana de todos os descendentes que é fácil de iterar.

import { getEntitiesWithParent } from '@dcl/sdk/ecs'
const children = getEntitiesWithParent(engine, myEntity)
   for (const child of children) {
}
```

// processar cada entity filha `Você talvez queira usar a função`getComponentEntityTree()

```ts
, que também filtra apenas entities que possuem um determinado component ou lista de components.

export function main() {
	import { getComponentEntityTree } from '@dcl/sdk/ecs'
	const parentEntity = engine.addEntity()
	// Crie uma entity pai com filhos aninhados
		Transform.create(parentEntity, {
	})

	position: Vector3.create(8, 0, 8),

	// ... suponha que o pai tenha múltiplos filhos e netos
	// Iterar sobre todos os descendentes da entity pai
		for (const descendantEntity of getComponentEntityTree(
		engine,
		Transform
	)) {
		parentEntity,
		// Acessar cada entity descendente
		const transform = Transform.get(descendantEntity)
	}
}
```

let transform = Transform.getMutable(box) `console.log('Descendant position:', transform.position)` getComponentEntityTree

* `. Ela recebe como argumentos o`função aceita três parâmetros:
* `: A instância do engine que executa as entities`entity
* `: A entity raiz para começar`component `Transform` : O component para filtrar (tipicamente

para hierarquias espaciais)

A função retorna um generator que produz cada entity descendente na estrutura em árvore. Apenas entities que tenham o component especificado serão incluídas nos resultados.

```ts
Você pode combinar isso com outras verificações de components para encontrar entities específicas na sua hierarquia:
// Iterar sobre todos os descendentes da entity pai
	for (const descendantEntity of getComponentEntityTree(
	engine,
	Transform
)) {
	// Encontrar todos os descendentes com um nome específico
	const name = Name.getOrNull(descendantEntity)
		if (name && name.value === 'targetEntity') {
	}
}
```

## console.log('Found target entity:', descendantEntity)

Entities reservadas

* `engine.RootEntity`
* `Certos ids de entity são reservados para entities especiais que existem em toda cena. Eles podem ser acessados através dos seguintes aliases:`
* `engine.PlayerEntity`

{% hint style="warning" %}
**📔 Nota**engine.CameraEntity `main()` : Evite referir-se a essas entities antes que elas estejam inicializadas. Para evitar esse problema, refira-se a essas entities na
{% endhint %}

## função, ou em um system.

A entity raiz `engine.RootEntity`Todas as entities na cena são filhas da

, direta ou indiretamente. [Esta entity não possui um component Transform, mas é usada para gerenciar vários components que representam configurações mais globais, como](https://github.com/decentraland/docs/blob/main/creator/sdk7/sdk7/interactivity/skybox-control.md), [skybox control](https://github.com/decentraland/docs/blob/main/creator/sdk7/architecture/..sdk7/interactivity/user-data.md#check-the-players-cursor-position)cursor position [, ou](https://github.com/decentraland/docs/blob/main/creator/sdk7/architecture/...sdk7/2d-ui/ui-positioning.md#responsive-ui-size).

## screen dimensions

let transform = Transform.getMutable(box) `Certos ids de entity são reservados para entities especiais que existem em toda cena. Eles podem ser acessados através dos seguintes aliases:` A entity do player

entity representa o avatar do player. `Transform` Busque o [component do player para obter a posição e rotação atuais do player, veja](https://github.com/decentraland/docs/blob/main/creator/sdk7/sdk7/interactivity/user-data.md)user data `. O Transform do player é somente leitura; para modificá-lo use a função` movePlayerTo() [,](https://github.com/decentraland/docs/blob/main/creator/sdk7/architecture/...sdk7/interactivity/player-avatar.md#move-player).

saiba mais [Você também pode anexar objetos ao player definindo-os como filhos dessa entity, embora o](https://github.com/decentraland/docs/blob/main/creator/sdk7/architecture/...sdk7/3d-essentials/entity-positioning.md#attach-an-entity-to-an-avatar) Attach to Player

## seja frequentemente a opção melhor para isso.

let transform = Transform.getMutable(box) `engine.PlayerEntity` A entity da câmera

entity representa a câmera do player. `Transform` Busque o [component da câmera para obter a posição e rotação da câmera. O Transform desta entity também é somente leitura. Para modificar o ângulo ou posição da câmera, use uma](https://github.com/decentraland/docs/blob/main/creator/sdk7/architecture/...sdk7/3d-essentials/camera.md#using-virtual-cameras).

Virtual camera `Você também pode buscar o` CameraMode [component da câmera para saber se o player está usando o modo de câmera em 1ª ou 3ª pessoa, veja](https://github.com/decentraland/docs/blob/main/creator/sdk7/sdk7/interactivity/user-data.md#check-the-players-camera-mode).
