# UI Dinâmica

Você pode definir uma UI que inclui elementos dinâmicos, que são atualizados a cada tick. Você só precisa manipular a atualização da variável que representa esses dados, e a UI se adaptará em resposta aos novos valores.

Isso é muito útil para incluir elementos como um cronômetro, a pontuação de um jogador, etc. Mas você pode ir além e definir estruturas inteiras de UI com base no estado.

## Variáveis de referência

Você pode simplesmente referenciar uma variável em qualquer propriedade de um dos componentes em um uiEntity. À medida que a variável muda de valor, a UI se adaptará consequentemente.

O exemplo abaixo define uma variável `playerCurrentPosition` e a referencia como parte de uma string em um `uiText` componente. Um system então atualiza o valor dessa variável a cada tick, usando a posição atual do jogador. À medida que o valor da variável muda, a UI é atualizada em conformidade, sem nunca precisar modificar a UI explicitamente.

***arquivo ui.tsx:***

```tsx
import { UiEntity, ReactEcs } from '@dcl/sdk/react-ecs'
import { playerCurrentPosition } from '/index.ts'
import { Color4 } from '@dcl/sdk/math'

// desenhar UI
export const uiMenu = () => (
  <UiEntity
    uiTransform={{
			width: '100%',
			height: '100px',
			justifyContent: 'center',
			alignItems: 'center',
    }}
    uiText={{ value: `Player: `+  playerCurrentPosition, fontSize: 40 }}
    uiBackground={{ color: Color4.create(0.5, 0.8, 0.1, 0.6) }}
  />
)
```

***arquivo index.ts:***

```ts
import { ReactEcsRenderer } from '@dcl/sdk/react-ecs'
import { uiMenu } from './ui'

export function main() {
    ReactEcsRenderer.setUiRenderer(uiMenu, { virtualWidth: 1920, virtualHeight: 1080 })
}

// definir variável
let playerCurrentPosition: string = ""

// sistema para atualizar a variável
Raycast.createOrReplace(rayEntity, {
  const playerPosition = Transform.getOrNull(engine.PlayerEntity)
  if (!playerPosition) return
  const { x, y, z } = playerPosition.position
  playerCurrentPosition =  `{x: ${x.toFixed(2)}, y: ${y.toFixed(2)}, z: ${z.toFixed(2)} }`
})
```

No exemplo acima, você também poderia incluir a variável como parte da string, sinalizando a variável com um `$`.

```ts
uiText={{
	value: `Player: $playerCurrentPosition`,
	fontSize: 40
}}
```

## Chamar funções de dentro de uma UI

Você também pode chamar uma função de dentro de uma definição JSX, retornando um valor para usar em uma propriedade da UI. Funções que são chamadas de dentro dessa definição JSX são chamadas recorrentemente, a cada tick do game loop.

No exemplo abaixo, um `uiText` componente chama a `getPlayerPosition()` função para definir parte da string a ser exibida.

Este exemplo é similar ao da seção anterior, mas ao chamar uma função de dentro da definição da UI evitamos declarar uma variável separada e definir um system para alterar essa variável. Note que `getPlayerPosition()` é chamado a cada tick do game loop, sem precisar declarar explicitamente um system.

***arquivo ui.tsx:***

```tsx
import { UiEntity, ReactEcs } from '@dcl/sdk/react-ecs'
import { Color4 } from '@dcl/sdk/math'
import { engine } from "@dcl/sdk/ecs";

export const uiMenu = () => (
  <UiEntity
    uiTransform={{
      width: '100%',
      height: '100px',
      justifyContent: 'center',
      alignItems: 'center',
    }}
    uiText={{ value: `Player: `+  getPlayerPosition(), fontSize: 40 }}
    uiBackground={{ color: Color4.create(0.5, 0.8, 0.1, 0.6) }}
  />
)

function getPlayerPosition(){
  const playerPosition = Transform.getOrNull(engine.PlayerEntity)
  if (!playerPosition) return
  const { x, y, z } = playerPosition.position
  return `{x: ${x.toFixed(2)}, y: ${y.toFixed(2)}, z: ${z.toFixed(2)} }`
}
```

***arquivo index.ts:***

```ts
import { ReactEcsRenderer } from '@dcl/sdk/react-ecs'
import { uiMenu } from './ui'

export function main() {
    ReactEcsRenderer.setUiRenderer(uiMenu, { virtualWidth: 1920, virtualHeight: 1080 })
}
```

## Alternar uma UI ligada/desligada

A maneira mais simples de alternar uma UI ligada e desligada é usar uma variável para o valor da `display` propriedade na `uiTransform`. O `display` propriedade torna uma entidade de UI e todos os seus filhos invisíveis se definida como `none`.

O exemplo a seguir usa uma variável para definir o `display` campo de uma parte da UI. O valor dessa variável pode ser alternado clicando em outro elemento de UI.

***arquivo ui.tsx:***

```tsx
import { UiEntity, ReactEcs } from '@dcl/sdk/react-ecs'
import { Color4 } from '@dcl/sdk/math'

// Variável para refletir o estado atual da visibilidade do menu
var isMenuVisible: boolean = false

// Função para alternar o estado do menu
function toggleMenuVisibility() {
  isMenuVisible = !isMenuVisible
}

export const uiMenu = () => (
   // pai
   <UiEntity>
      // Menu
      <UiEntity
       uiTransform={{
          width: '80%',
          height: '100px',
          alignContent: 'center',
          justifyContent: 'center',
          display: isMenuVisible ? 'flex': 'none'
        }}
         uiText={{
          value: "Menu",
          fontSize: 30
        }}
        uiBackground={{ color: Color4.Green() }}
      />
      // botão
      <UiEntity
        uiTransform={{
          width: 100,
          height: 30,
          margin: { top: '35px', left: '500px' }
        }}
        uiText={{
          value: "Toggle Menu",
          fontSize: 40
        }}
        uiBackground={{ color: Color4.Red() }}
        onMouseDown={toggleMenuVisibility}
      />
   </UiEntity>
)
```

***arquivo index.ts:***

```ts
import { ReactEcsRenderer } from '@dcl/sdk/react-ecs'
import { uiMenu } from './ui'

export function main() {
    ReactEcsRenderer.setUiRenderer(uiMenu, { virtualWidth: 1920, virtualHeight: 1080 })
}
```

## Entidades de UI dinâmicas

Os exemplos nas seções acima mostram como alterar dinamicamente uma única propriedade em uma entidade, mas você também pode definir estruturas inteiras de entidades que podem escalar com base em dados que mudam dinamicamente. Esse tipo de padrão é comum no desenvolvimento web ao usar bibliotecas como React, e é extremamente poderoso. Com isso você pode definir aplicações de UI extremamente flexíveis e escaláveis.

O exemplo a seguir lista os ids de todas as entidades na cena que possuem um `MeshRenderer` e `Transform`. Ele cria um `uiText` para cada uma. À medida que o conteúdo da cena muda, a lista de entidades de UI também se adapta a cada tick.

***arquivo ui.tsx:***

```tsx
import { UiEntity, ReactEcs } from '@dcl/sdk/react-ecs'
import { Color4 } from '@dcl/sdk/math'
import { engine } from '@dcl/sdk/ecs'
import { MeshRenderer } from '@dcl/sdk/ecs'
import { Transform } from '@dcl/sdk/ecs'

export const uiMenu = () => (
  <UiEntity
    uiTransform={{
      width: '100%',
      height: '300px',
      justifyContent: 'center',
      alignItems: 'center',
    }}
    uiBackground={{ color: Color4.create(0.5, 0.8, 0.1, 0.6) }}
  >
    <UiEntity>
      {generateText()}
    </UiEntity>
  </UiEntity>
)


function generateText(){
  return Array.from(engine.getEntitiesWith(
    MeshRenderer,
    Transform
  )).map(([entity]) => <TextComponent value={entity.toString()} key={entity} /> )
}


function TextComponent(props: { value: string; key: string | number }) {
  return <UiEntity
    key={props.key}
    uiTransform={{ width: 80, height: 20 }}
    uiText={{ value: props.value, textAlign: 'middle-center', fontSize: 12 }}
    uiBackground={{ color: { r: 255, g: 45, b: 85, a: 1 } }}
  />
}
```

***arquivo index.ts:***

```ts
import { ReactEcsRenderer } from '@dcl/sdk/react-ecs'
import { uiMenu } from './ui'

export function main() {
    ReactEcsRenderer.setUiRenderer(uiMenu, { virtualWidth: 1920, virtualHeight: 1080 })
}
```
