> 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-pt/scenes-sdk7/interatividade/raycasting.md).

# Raycasting

Use raycasting para traçar uma linha no espaço e consultar colisões com entities na scene.

Raycasting é uma ferramenta fundamental no desenvolvimento de jogos. Com raycasting, você pode traçar uma linha imaginária no espaço e verificar se alguma Entity é interceptada por essa linha. Isso é útil para calcular linhas de visão, trajetórias de balas, algoritmos de pathfinding e muitas outras aplicações.

Quando um jogador pressiona o botão do pointer, ou o botão primário ou secundário, um ray é traçado da posição do jogador na direção para a qual ele está olhando, veja [eventos de botão](/creator/content-creator-pt/scenes-sdk7/interatividade/button-events/click-events.md) para mais detalhes sobre isso. Este documento aborda como traçar um ray invisível a partir de qualquer posição e direção arbitrárias, independentemente das ações do jogador, o que você pode usar em muitos outros cenários.

Observe que raycasts só atingem objetos com colliders. Então, se você quiser detectar hits de ray contra um modelo 3D, ou:

* O modelo deve conter [collider meshes](/creator/content-creator-pt/modelagem-3d-e-animacoes/colliders.md).
* O `GLTFContainer` deve ser configurado para usar a [geometria visível com collision masks](/creator/content-creator-pt/scenes-sdk7/fundamentos-de-conteudo-3d/colliders.md#colliders-on-3d-models).
* Adicione um [componente MeshCollider](/creator/content-creator-pt/scenes-sdk7/fundamentos-de-conteudo-3d/colliders.md).

Também é uma boa prática atribuir [collision layers](/creator/content-creator-pt/scenes-sdk7/fundamentos-de-conteudo-3d/colliders.md#collision-layers) personalizadas a modelos 3D, para que os rays só precisem calcular colisões contra as Entities relevantes, em vez de contra tudo o que tem um collider.

## Criar um ray

Todos os rays têm um ponto de origem e uma direção. O ponto de origem é baseado na posição de uma Entity, usando os valores do componente Transform da Entity. A direção de um ray pode ser definida de 4 formas diferentes:

* **local**: Uma direção relativa à direção para a frente da Entity, afetada também pela transformação de quaisquer Entities pai. Isso é útil para detectar obstáculos à frente de veículos, respeitando sua orientação.
* **global**: Ignora a rotação da Entity e aponta para uma direção como se a rotação da Entity fosse 0. Isso é útil, por exemplo, para apontar sempre para baixo.
* **alvo global**: Traça uma linha entre a posição da Entity e uma posição global alvo na cena. Ignora a rotação da Entity. Útil, por exemplo, para criar jogos de tower defense, onde a torre de cada estrutura pode apontar para uma coordenada precisa no espaço.
* **Entity alvo**: Traça uma linha entre a posição da Entity e a posição de uma segunda Entity alvo. Ignora a rotação de ambas as Entities.

O código a seguir cria um raycast com uma direção local:

```ts
const myEntity = engine.addEntity()
Transform.create(myEntity, {
  position: Vector3.create(4, 1, 4),
})

raycastSystem.registerLocalDirectionRaycast(
  {
    entity: myEntity,
    opts: { direction: Vector3.Forward() },
  },
  function (raycastResult) {
    // função de callback
  }
)
```

Use as seguintes funções para criar raycasts fornecendo a direção de diferentes formas:

* `raycastSystem.registerLocalDirectionRaycast()`: cria um raycast com uma **local** direção `direction` espera um `Vector3` que descreve um vetor relativo à Entity e à sua rotação (por exemplo, `Vector3.Forward()` acabaria usando o vetor forward do Transform da Entity)
* `raycastSystem.registerGlobalDirectionRaycast()`: cria um raycast com uma **global** direção `direction` espera um `Vector3` que descreve a direção global.
* `raycastSystem.registerGlobalTargetRaycast()`: cria um raycast com uma direção definida por uma **alvo global** posição `target` espera um `Vector3` que descreve uma posição global na cena.
* `raycastSystem.registerTargetEntityRaycast()`: cria um raycast com uma direção definida em direção a uma **Entity alvo** posição `targetEntity` o campo espera uma referência a uma Entity; a posição desta Entity será usada como alvo do ray.

Os seguintes campos opcionais estão disponíveis ao criar um ray com qualquer um dos métodos acima:

* `maxDistance`: *number* para definir o comprimento com que este ray será traçado. Se não for definido, o padrão é 16 metros.
* `queryType`: *RaycastQueryType* valor de enum, para definir se o ray retornará todas as Entities atingidas ou apenas a primeira. As seguintes opções estão disponíveis:
  * `RaycastQueryType.RQT_HIT_FIRST`: *(padrão)* retorna apenas a primeira Entity atingida, começando do ponto de origem.
  * `RaycastQueryType.RQT_QUERY_ALL`: retorna todas as Entities atingidas, da origem até a distância máxima do ray.
* `originOffset`: Em vez de iniciar o raycast na posição de origem da Entity, adicione um offset para iniciar a consulta a partir de uma posição relativa. Você pode, por exemplo, usar um pequeno offset para evitar que o ray colida com o próprio collider da Entity. Se não for definido, o padrão é `Vector3.Zero()`.
* `collisionMask`: Detecta colisões apenas com determinadas collision layers. Use isso junto com uma collision layer personalizada, ou para detectar apenas a physics layer ou a pointer events layer. Veja [collision layers](/creator/content-creator-pt/scenes-sdk7/fundamentos-de-conteudo-3d/colliders.md#collision-layers). Se não for definido, a camada padrão usada é `ColliderLayer.CL_PHYSICS`.
* `continuous`: Se verdadeiro, continuará executando uma consulta de raycast em cada frame. Se falso, o ray será usado apenas no frame atual. Se não for definido, o padrão é falso.
* Ao definir a direção com uma direção local ou glocal, o `direction` campo tem como padrão `Vector3.Forward()`.
* Ao definir a direção com um alvo global, o `target` campo tem como padrão `Vector3.Zero()`.
* Ao definir a direção com um alvo de Entity, o `targetEntity` campo tem como padrão a Entity raiz da cena, localizada em `Vector3.Zero()`.

{% hint style="warning" %}
**📔 Nota**: O `continuous` property deve ser usado com cautela, pois executar uma consulta de raycast em cada frame pode ser muito caro em termos de performance. Sempre que possível, use um sistema (ou a `interval` função na biblioteca Utils) para executar consultas de raycast em um intervalo regular mais espaçado, veja [raycasting recorrente](#recurrent-raycasting).
{% endhint %}

A seguir estão exemplos usando cada um dos quatro métodos para determinar a direção do ray:

```ts
// LOCAL DIRECTION RAYCAST
raycastSystem.registerLocalDirectionRaycast(
  {
    entity: myEntity,
    opts: {
      queryType: RaycastQueryType.RQT_QUERY_ALL,
      direction: Vector3.Forward(),
      maxDistance: 30,
    },
  },
  function (raycastResult) {
    console.log(raycastResult.hits)
  }
)
// GLOBAL DIRECTION RAYCAST
raycastSystem.registerGlobalDirectionRaycast(
  {
    entity: myEntity,
    opts: {
      queryType: RaycastQueryType.RQT_QUERY_ALL,
      direction: Vector3.Forward(),
      maxDistance: 30,
    },
  },
  function (raycastResult) {
    console.log(raycastResult.hits)
  }
)
// GLOBAL TARGET POSITION RAYCAST
raycastSystem.registerGlobalTargetRaycast(
  {
    entity: myEntity,
    opts: {
      queryType: RaycastQueryType.RQT_QUERY_ALL,
      target: Vector3.Zero(),
    },
  },
  (raycastResult) => {
    console.log(raycastResult.hits)
  }
)
// TARGET ENTITY RAYCAST
const targetEntity = engine.addEntity()
Transform.create(targetEntity, { position: Vector3.create(8, 1, 10) })

raycastSystem.registerTargetEntityRaycast(
  {
    entity: myEntity,
    opts: {
      queryType: RaycastQueryType.RQT_QUERY_ALL,
      targetEntity: targetEntity,
    },
  },
  (raycastResult) => {
    console.log(raycastResult.hits)
  }
)
```

{% hint style="warning" %}
**📔 Nota**: `raycastSystem`, `RaycastQueryType` e `ColliderLayer` devem ser importados via

> `import { raycastSystem, RaycastQueryType, ColliderLayer } from "@dcl/sdk/ecs"`

Veja [Imports](/creator/content-creator-pt/scenes-sdk7/primeiros-passos/coding-scenes.md#imports) para saber como lidar facilmente com isso.
{% endhint %}

## Resultado do raycast

A função de callback que trata o raycast recebe um objeto contendo dados sobre o próprio ray e quaisquer Entities que tenham sido atingidas.

* `globalOrigin`: A posição onde o ray se originou, relativa à cena.
* `direction`: A direção global para a qual o ray estava apontando, como um `Vector3`.
* `hits`: Um array com um objeto para cada Entity que foi atingida. Se não houver Entities atingidas, este array fica vazio. Se o raycast usou `RaycastQueryType.RQT_HIT_FIRST`, este array conterá apenas um objeto.

Cada objeto no `hits` array inclui:

* `entityId`: Número de Id da Entity que foi atingida pelo ray.
* `meshName`: *String* com o nome interno do mesh específico no modelo 3D que foi atingido. Isso é útil quando um modelo 3D é composto por vários meshes.
* `position`: *Vector3* para a posição onde o ray intersectou a Entity atingida (relativa à cena)
* `length`: Comprimento do ray desde sua origem até a posição onde ocorreu o hit contra a Entity.
* `normalHit`: *Vector3* para a normal da superfície atingida no espaço mundial.
* `globalOrigin`: *Vector3* para a posição onde o ray se origina (relativa à cena)
* `direction`: A direção global para a qual o ray estava apontando, como um `Vector3`.

O exemplo a seguir percorre as Entities que foram atingidas:

```ts
const myEntity = engine.addEntity()
Transform.create(myEntity, {
  position: Vector3.create(4, 1, 4),
})

raycastSystem.registerLocalDirectionRaycast(
  {
    entity: myEntity,
    opts: {
      queryType: RaycastQueryType.RQT_QUERY_ALL,
      direction: Vector3.Forward(),
      maxDistance: 30,
    },
  },
  function (raycastResult) {
    if (raycastResult.hits.length > 0) {
      for (const hit of raycastResult.hits) {
        if (hit.entityId) {
          console.log('hit entity ', hit.entityId)
        }
      }
    } else {
      console.log('nenhuma Entity atingida')
    }
  }
)
```

{% hint style="warning" %}
**📔 Nota**: Você pode obter um resultado de raycast ao atingir uma Entity em uma cena diferente.
{% endhint %}

## Tratar Entities atingidas

Quando você obtém um resultado de raycast que atingiu uma Entity, você pode usar o `entityId` para interagir com a Entity e seus components. Uma Entity é [nada mais do que um número](/creator/content-creator-pt/scenes-sdk7/arquitetura/entities-components.md#overview), então o `entityId` próprio valor pode ser interpretado como um `Entity` tipo.

```ts
const hitEntity = hit.entityId as Entity
const transform = Transform.get(hitEntity)
console.log(transform.position)
```

## Collision layers

É uma boa prática verificar colisões apenas contra Entities relevantes, para tornar a cena mais performática. O `collisionMask` campo permite listar apenas collision layers específicas — a camada de physics (paredes e pisos da cena), a camada do pointer (pointer events), as camadas dos players (avatars), ou 8 camadas personalizadas que você pode atribuir livremente. Veja [collision layers](/creator/content-creator-pt/scenes-sdk7/fundamentos-de-conteudo-3d/colliders.md#collision-layers).

Por padrão, o `collisionMask` campo está definido como `ColliderLayer.CL_PHYSICS`. Você pode alterar este valor para listar outras camadas, ou combinar várias com o `|` separador.

```ts
raycastSystem.registerLocalDirectionRaycast(
  {
    entity: myEntity,
    opts: {
      queryType: RaycastQueryType.RQT_QUERY_ALL,
      direction: Vector3.Forward(),
      maxDistance: 30,
      collisionMask:
        ColliderLayer.CL_CUSTOM1 |
        ColliderLayer.CL_CUSTOM3 |
        ColliderLayer.CL_POINTER,
    },
  },
  (raycastResult) => {
    log(raycastResult.hits)
  }
)
```

## Raycasting recorrente

Ao usar as funções do `raycastSystem`raycastSystem `continuous` campo para *true* para executar uma consulta e a função de callback em cada tick do loop do jogo.

O exemplo a seguir continuará executando a consulta de raycast a partir deste ponto em diante

```ts
raycastSystem.registerLocalDirectionRaycast(
  {
    entity: myEntity,
    opts: {
      queryType: RaycastQueryType.RQT_QUERY_ALL,
      direction: Vector3.Forward(),
      maxDistance: 30,
      continuous: true,
    },
  },
  function (raycastResult) {
    log(raycastResult.hits)
  }
)
```

{% hint style="warning" %}
**📔 Nota**: O `continuous` property deve ser usado com cautela, pois executar uma consulta de raycast em cada frame pode ser muito caro em termos de performance.
{% endhint %}

Quando não for mais necessário, remova quaisquer raycasts recorrentes. Para isso, você deve usar `raycastSystem.removeRaycasterEntity`.

```ts
raycastSystem.removeRaycasterEntity(myEntity)
```

Sempre que possível, use um sistema (ou a `interval` função na biblioteca Utils) para executar consultas de raycast em um intervalo regular mais espaçado, como apenas uma vez por segundo, ou a cada quinto de segundo.

```typescript
// custom components
const CubeOscilator = engine.defineComponent('CubeOscilator', {
  t: Schemas.Float,
})

const TimerComponent = engine.defineComponent('TimerComponent', {
  t: Schemas.Float,
})

const RAY_INTERVAL = 0.1

// check rays
engine.addSystem((dt) => {
  for (const [entity] of engine.getEntitiesWith(TimerComponent)) {
    const timer = TimerComponent.getMutable(entity)
    timer.t += dt

    if (timer.t > RAY_INTERVAL) {
      timer.t = 0
      raycastSystem.registerGlobalDirectionRaycast(
        {
          entity: myEntity,
          opts: {
            queryType: RaycastQueryType.RQT_HIT_FIRST,
            direction: Vector3.Forward(),
            maxDistance: 16,
          },
        },
        function (raycastResult) {
          log(raycastResult.hits)
        }
      )
    }
  }
})

TimerComponent.create(engine.addEntity())

// oscillating cube system
engine.addSystem((dt) => {
  for (const [entity, cube] of engine.getEntitiesWith(
    CubeOscilator,
    Transform
  )) {
    CubeOscilator.getMutable(entity).t += dt
    Transform.getMutable(entity).position.y = 2 + Math.cos(cube.t)
  }
})

// create cube
const cubeEntity = engine.addEntity()
Transform.create(cubeEntity, { position: { x: 8, y: 1, z: 8 } })
CubeOscilator.create(cubeEntity)
MeshRenderer.setBox(cubeEntity)
MeshCollider.setBox(cubeEntity)
```

O exemplo acima executa um raycast recorrente a cada 0,1 segundos. Ele usa um componente de timer e a propriedade dt de um system para marcar esses intervalos de forma uniforme. Ele também inclui um cubo que oscila para cima e para baixo, controlado por outro system, para entrar e sair do caminho do ray. `dt` propriedade para sincronizar isso de forma uniforme. Ele também inclui um cubo que oscila para cima e para baixo, controlado por outro system, para entrar e sair do caminho do ray.

{% hint style="info" %}
**💡 Dica**: Use a `interval` função na biblioteca [SDK Utils](https://github.com/decentraland/sdk7-utils) para uma forma mais simples de executar uma função em um intervalo fixo.
{% endhint %}

## Raycasts via um system

Outra forma de executar raycasts recorrentes é executá-los de dentro da função recorrente de um system. Isso permite que você tenha muito mais controle sobre quando e como eles funcionam. Em vez de registrar uma função de callback, você pode executar uma consulta de raycast com `raycastSystem.registerRaycast` e então verificar os dados retornados por essa operação, tudo dentro da função do system.

Observe que, como o raycast é executado em um system, o resultado só estará disponível no tick seguinte, exigindo duas execuções do system. Uma para registrar o raycast para o frame seguinte, e o frame seguinte para processar seu resultado.

```ts
engine.addSystem((deltaTime) => {
		const result = raycastSystem.registerRaycast(
			myEntity,
			raycastSystem.localDirectionOptions({
				collisionMask: ColliderLayer.CL_CUSTOM1 | ColliderLayer.CL_CUSTOM3 | ColliderLayer.CL_POINTER,
				originOffset: Vector3.create(0, 0.4, 0),
				maxDistance: 16,
				queryType: RaycastQueryType.RQT_HIT_FIRST,
				direction: Vector3.Forward(),
				continuous: true // não use em excesso a propriedade 'continuous' porque raycasting é caro para a performance
			})
		)
		if (result) {
			// faça algo
		}
	})
```

## Colidir com o jogador

Você pode detectar avatars diretamente com raycasts incluindo qualquer uma das collision layers de avatar na mask:

* `ColliderLayer.CL_PLAYER`: corresponde a qualquer avatar — o jogador local E qualquer outro jogador renderizado na cena.
* `ColliderLayer.CL_MAIN_PLAYER`: corresponde apenas ao jogador local (main).

Ambas as layers podem ser combinadas ou usadas independentemente. O `collisionMask` padrão para um raycast é `CL_PHYSICS`, que NÃO atinge avatars — você precisa habilitar isso explicitamente.

```ts
// Atinja apenas o jogador local (ignore outros avatars)
raycastSystem.registerLocalDirectionRaycast(
  {
    entity: myEntity,
    opts: {
      direction: Vector3.Forward(),
      collisionMask: ColliderLayer.CL_MAIN_PLAYER,
    },
  },
  (raycastResult) => {
    if (raycastResult.hits.length > 0) {
      console.log('Atingiu o jogador local')
    }
  }
)

// Atinja qualquer avatar (local + remoto)
raycastSystem.registerLocalDirectionRaycast(
  {
    entity: myEntity,
    opts: {
      direction: Vector3.Forward(),
      collisionMask: ColliderLayer.CL_PLAYER,
    },
  },
  (raycastResult) => {
    // raycastResult.hits[i].entityId é 0 para hits de avatar remoto (sem id de Entity local da cena)
    console.log(raycastResult.hits)
  }
)
```

Quando um raycast atinge o jogador local, o `hit.entityId` é `engine.PlayerEntity`. Hits em avatars remotos não carregam um id de Entity local da cena (o campo é `0`) porque o jogador remoto não é uma Entity no mundo da sua cena — mas o hit ainda é reportado com sua `position`, `length`, `normalHit`e outros dados geométricos.

{% hint style="info" %}
**💡 Dica**: Para detectar apenas **outros** players (excluindo o jogador local), use `CL_PLAYER` e filtre `hit.entityId !== engine.PlayerEntity` no callback.
{% endhint %}

## Raycasts a partir do jogador

Para traçar um ray a partir da posição do jogador na direção para a qual a câmera está apontando, você pode traçar um ray usando a câmera ou o avatar [Reserved entities](/creator/content-creator-pt/scenes-sdk7/arquitetura/entities-components.md#reserved-entities).

{% hint style="info" %}
**💡 Dica**: Na maioria dos casos, talvez seja melhor usar [Pointer events](/creator/content-creator-pt/scenes-sdk7/interatividade/button-events/click-events.md) em vez de raycasts.
{% endhint %}

O exemplo a seguir traça um ray da posição da câmera do jogador para a frente, usando a `engine.CameraEntity` Entity.

```ts
raycastSystem.registerGlobalDirectionRaycast(
  {
    entity: engine.CameraEntity,
    opts: {
      queryType: RaycastQueryType.RQT_HIT_FIRST,
      direction: Vector3.rotate(
        Vector3.Forward(),
        Transform.get(engine.CameraEntity).rotation
      ),
    },
  },
  function (raycastResult) {
    console.log(raycastResult)
  }
)
```

{% hint style="warning" %}
**📔 Nota**: Tenha em mente que, em 3rd person, o cursor pode no futuro não se comportar da mesma forma que em 1st person. Recomenda-se usar isso apenas se o jogador estiver em 1st person.
{% endhint %}

## Raycast a partir da posição do cursor

Você também pode traçar um ray a partir da posição do cursor do jogador para dentro do mundo 3D. Isso pode ser usado para arrastar objetos, shooters etc.

Neste exemplo, detectamos quando o jogador pressiona a tecla E e então traçamos um ray da posição do cursor para dentro do mundo 3D. Em seguida, verificamos se o ray atingiu alguma Entity e, se sim, fazemos algo com ela.

```ts
import { engine, Entity, InputAction, inputSystem, PointerEventType, RaycastQueryType, raycastSystem, TextShape, Transform } from '@dcl/sdk/ecs'
import { PrimaryPointerInfo } from '@dcl/sdk/ecs'

let cooldown = 1
let rayFrequency = 0.1
let mousePressed = false

export function main() {
   engine.addSystem(rayCastSystem)
}

const rayCastSystem = (t: number) => {

    if (inputSystem.isTriggered(InputAction.IA_PRIMARY, PointerEventType.PET_DOWN)) {
      mousePressed = true
    }

    if (inputSystem.isTriggered(InputAction.IA_PRIMARY, PointerEventType.PET_UP)) {
      mousePressed = false
    }

    if (!mousePressed) {
      cooldown = 0
      raycastSystem.removeRaycasterEntity(engine.CameraEntity)
      return
    }

    cooldown += t
    if (cooldown < rayFrequency) return
    cooldown = 0

    const pointerInfo = PrimaryPointerInfo.getOrCreateMutable(engine.RootEntity)
    let dir = pointerInfo.worldRayDirection

    raycastSystem.registerGlobalDirectionRaycast(
      {
        entity: engine.CameraEntity,
        opts: {
          queryType: RaycastQueryType.RQT_HIT_FIRST,
          direction: dir,
        },
      },
      function (raycastResult) {
        let result = raycastResult.hits[0]

        // faça algo na posição do impacto
        if (result && result.position) {
          console.log("x:", result.position.x, ", y:", result.position.y, ", z:", result.position.z)
        }

        // faça algo com a Entity atingida
        const entity = result.entityId as Entity
        if (entity) {
          console.log("entity: ", entity)
        }
      }
    )
}

```

{% hint style="info" %}
**💡 Dica**: Neste exemplo, usamos o botão principal (E) para disparar o raycast. Não usamos o botão do pointer (clique esquerdo) porque clicar e arrastar também altera o ângulo da camera por padrão. Se você quiser impedir a rotação da camera enquanto arrasta, você pode usar uma [Virtual Camera](/creator/content-creator-pt/scenes-sdk7/fundamentos-de-conteudo-3d/camera.md) para definir o ângulo da camera como fixo.
{% endhint %}

## Sintaxe avançada

### Criar um componente raycast

Um componente Raycast descreve o raio invisível usado para consultar entities que se intersectam. O raio é traçado a partir da posição da Entity, conforme definido pelo componente Transform e afetado pelo de quaisquer entities pai. A direção pode ser definida de várias maneiras,

Os rays são definidos usando os seguintes dados:

* `direction`: Um objeto que contém um `$case` campo para selecionar o tipo de direção, e um campo adicional que dependerá desse tipo, que determina essa direção. Os valores aceitos para `$case`:
  * `'localDirection'`: Uma direção relativa à direção para a frente da Entity, também afetada pela transformação de quaisquer entities pai. Isso é útil para detectar obstáculos à frente de veículos respeitando sua orientação. A rotação é definida pelo `localDirection` que descreve uma rotação. `Vector3` that describes a rotation.
  * `'globalDirection'`: Ignora a rotação da Entity, e aponta para uma direção como se a rotação da Entity fosse 0. Isso é útil, por exemplo, para apontar sempre para baixo. A rotação é definida pelo `globalDirection` que descreve uma rotação. `Vector3` that describes a rotation.
  * `'globalTarget'`: Traça uma linha entre a posição da Entity e uma posição global alvo na Scene. Ignora a rotação da Entity. Útil para criar jogos de tower defense, em que a torreta de cada torre pode apontar para uma coordenada precisa no espaço. O alvo é definido pelo `globalTarget` que descreve uma rotação. `Vector3` que descreve a posição global.
  * `'targetEntity'`: Traça uma linha entre a posição da Entity e a posição de uma segunda Entity alvo. Ignora a rotação de ambas as entities. O alvo é definido pelo `targetEntity` campo, contendo uma referência à Entity.
* `maxDistance`: *number* para definir o comprimento com que este raio será traçado.
* `queryType`: *RaycastQueryType* valor de enum, para definir se o ray retornará todas as Entities atingidas ou apenas a primeira. As seguintes opções estão disponíveis:
  * `RaycastQueryType.RQT_HIT_FIRST`: retorna apenas a primeira Entity atingida, a partir do ponto de origem.
  * `RaycastQueryType.RQT_QUERY_ALL`: retorna todas as Entities atingidas, da origem até a distância máxima do ray.
* `collisionMask`: Detecta colisões apenas com determinadas collision layers. Use isso junto com uma collision layer personalizada, ou para detectar apenas a physics layer ou a pointer events layer. Veja [collision layers](/creator/content-creator-pt/scenes-sdk7/fundamentos-de-conteudo-3d/colliders.md#collision-layers). Por padrão, o valor é `ColliderLayer.CL_POINTER | ColliderLayer.CL_PHYSICS`.
* `originOffset`: Em vez de iniciar o raycast a partir da posição de origem da Entity, adicione um offset para iniciar a consulta a partir de uma posição relativa. Por exemplo, você pode usar um pequeno offset para impedir que o raio colida com o próprio modelo 3D da Entity.
* `continuous`: Se true, continuará executando uma consulta raycast a cada frame. Se false, o raio será usado apenas no frame atual. Por padrão, este valor é false.

{% hint style="warning" %}
**📔 Nota**: O `continuous` property deve ser usado com cautela, pois executar uma consulta de raycast em cada frame pode ser muito caro em termos de performance. Sempre que possível, use um sistema (ou a `interval` função na biblioteca Utils) para executar consultas de raycast em um intervalo regular mais espaçado, veja [raycasting recorrente](#recurrent-raycasting).
{% endhint %}

O exemplo a seguir usa uma rotação global para determinar a direção e retorna apenas a primeira Entity atingida no frame em que o raio é enviado.

```typescript
const entity1 = engine.addEntity()

Transform.create(entity1, {
  position: Vector3.create(8, 1, 0)
})

Raycast.createOrReplace(entity1, {
  direction: {
    $case: "globalDirection",
    globalDirection: Vector3.create(0, 0, 1)
  },
  maxDistance: 16,
  queryType: RaycastQueryType.RQT_HIT_FIRST
})
```

O exemplo abaixo lança um raio na direção para a frente da Entity, retornando apenas o primeiro item atingido. Ele faz isso continuamente. Também inclui um pequeno offset de 0,5 para impedir que o raio atinja o collider da própria Entity.

```typescript
const entity1 = engine.addEntity()

Transform.create(entity1, {
  position: Vector3.create(8, 1, 0)
})

Raycast.createOrReplace(entity1, {
  direction: {
    $case: "localDirection",
    localDirection: Vector3.Forward()
  },
  maxDistance: 16,
  queryType: RaycastQueryType.RQT_HIT_FIRST,
  originOffset: Vector3.create(0.5, 0, 0),
  continuous: true
})
```

Este exemplo traça um raio entre duas entities. Ele retorna todas as entities atingidas entre elas.

```ts
const entity1 = engine.addEntity()

Transform.create(entity1, {
  position: Vector3.create(8, 1, 0)
})

const entity2 = engine.addEntity()

Transform.create(entity2, {
  position: Vector3.create(0, 1, 8)
})

Raycast.createOrReplace(entity1, {
  direction: {
    $case: "targetEntity",
    targetEntity: entity2
  },
  maxDistance: 16,
  queryType: RaycastQueryType.RQT_QUERY_ALL
})
```

### Componente de resultados do Raycast

{% hint style="warning" %}
**📔 Nota**: A forma mais fácil de lidar com os resultados de raycast é usar `raycastSystem`, e registrar uma função de callback como parte da mesma instrução que cria o raio. O`RaycastResult` componente é usado internamente por essa interface, mas também é exposto para permitir uma lógica personalizada mais avançada.
{% endhint %}

Depois de criar um componente Raycast, a entity à qual este component é adicionado terá um `RaycastResult` component. Este component inclui informações sobre quaisquer hits do raio. Configure um system para verificar esses dados.

O `RaycastResult` component contém os seguintes dados:

* `globalOrigin`: A posição onde o ray se originou, relativa à cena.
* `direction`: A direção global para a qual o ray estava apontando, como um `Vector3`.
* `hits`: Um array com um objeto para cada Entity que foi atingida. Se não houver Entities atingidas, este array fica vazio. Se o raycast usou `RaycastQueryType.RQT_HIT_FIRST`, este array conterá apenas um objeto.

Cada objeto no `hits` array inclui:

* `entityId`: Número de Id da Entity que foi atingida pelo ray.
* `meshName`: *String* com o nome interno do mesh específico no modelo 3D que foi atingido. Isso é útil quando um modelo 3D é composto por vários meshes.
* `position`: *Vector3* para a posição onde o ray intersectou a Entity atingida (relativa à cena)
* `length`: Comprimento do ray desde sua origem até a posição onde ocorreu o hit contra a Entity.
* `normalHit`: *Vector3* para a normal da superfície atingida no espaço mundial.
* `globalOrigin`: *Vector3* para a posição onde o ray se origina (relativa à cena)
* `direction`: A direção global para a qual o ray estava apontando, como um `Vector3`.

O exemplo abaixo mostra como você pode acessar os resultados de uma entity individual usando um system:

```typescript

const rayEntity = engine.addEntity()

Transform.create(rayEntity, {
  position: Vector3.create(8, 1, 0)
})

// return all entities
Raycast.createOrReplace(rayEntity, {
  direction: {
    $case: "globalDirection",
    globalDirection: Vector3.create(0, 0, 1)
  },
  maxDistance: 16,
  queryType: RaycastQueryType.RQT_QUERY_ALL
})

engine.addSystem(() => {
  const rayResult = RaycastResult.get(rayEntity)
  console.log(rayResult.hits)
})
```

O próximo exemplo mostra como você pode acessar `RaycastResult` components de todas as entities na Scene, usando uma [consulta de component](/creator/content-creator-pt/scenes-sdk7/arquitetura/querying-components.md).

```typescript
engine.addSystem(() => {
  for (const [_, result] of engine.getEntitiesWith(RaycastResult)) {
    console.log(result.hits)
  }
})
```

{% hint style="warning" %}
**📔 Nota**: Os resultados de um raycast não chegam no mesmo tick do game loop em que você criou o raycast. Os resultados podem levar um ou vários ticks para chegar.
{% endhint %}

Em uma Scene na qual você usa vários tipos de rays para diferentes finalidades (como para path finding, verificação de line-of-sight, rastreamento de projéteis etc.), talvez você queira usar diferentes [collision layers](/creator/content-creator-pt/scenes-sdk7/fundamentos-de-conteudo-3d/colliders.md#collision-layers)para evitar calcular colisões irrelevantes.

{% hint style="info" %}
**💡 Dica**: Para ver um exemplo funcional de raycasting, consulte [`77,-1-raycast-unit-tests`](https://github.com/decentraland/sdk7-test-scenes/tree/main/scenes/77,-1-raycast-unit-tests) a Scene de teste, que afirma o comportamento do raycast por meio de `@dcl/sdk/testing` testes unitários em toda a `localDirection`, `globalDirection`, `globalTarget` e `targetEntity` formas de direção, incluindo rays lançados a partir de parents transformados. Para ver como se comportam os collider layers que um ray pode atingir, veja [`5,5-collider-layers`](https://github.com/decentraland/sdk7-test-scenes/tree/main/scenes/5,5-collider-layers).
{% endhint %}


---

# 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-pt/scenes-sdk7/interatividade/raycasting.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.
