# Raycasting

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 é intersectada por essa linha. Isso é útil para calcular linhas de visão, trajetórias de projéteis, algoritmos de pathfinding e muitas outras aplicações.

Quando um player pressiona o botão do pointer, ou o botão primary ou secondary, um ray é traçado da posição do player na direção para a qual ele está olhando, veja [eventos de botão](/creator/content-creator-pt/scenes-sdk7/interatividade/eventos-de-botao/click-events.md) para mais detalhes sobre isso. Este documento explica como traçar um ray invisível a partir de qualquer posição e direção arbitrárias, independente das ações do player, 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/modelacao-e-animacoes-3d/colliders.md).
* O `GLTFContainer` deve ser configurado para usar a [geometria visível com collision masks](/creator/content-creator-pt/scenes-sdk7/essenciais-de-conteudo-3d/colliders.md#colliders-on-3d-models).
* Adicione um [componente MeshCollider](/creator/content-creator-pt/scenes-sdk7/essenciais-de-conteudo-3d/colliders.md).

Também é uma boa prática atribuir [collision layers](/creator/content-creator-pt/scenes-sdk7/essenciais-de-conteudo-3d/colliders.md#collision-layers) personalizadas aos modelos 3D, para que os rays só precisem calcular colisões contra as entities relevantes, em vez de contra tudo 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 dessa entity. A direção de um ray pode ser definida de 4 maneiras diferentes:

* **local**: Uma direção relativa à direção frontal da entity, também afetada pela transformação de quaisquer entities pai. Isso é útil para detectar obstáculos à frente de veículos, respeitando seu rumo.
* **global**: Ignora a rotação da entity e aponta em uma direção como se a rotação da entity fosse 0. Isso é útil para, por exemplo, sempre apontar para baixo.
* **alvo global**: 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, por exemplo, para criar jogos de tower defense, em que a torre de cada torre pode apontar para uma coordenada específica 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 qualquer uma das 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 callback
  }
)
```

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

* `raycastSystem.registerLocalDirectionRaycast()`: cria um raycast com uma **local** direção. O `direction` campo 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. O `direction` campo 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. O `target` campo espera um `Vector3` que descreve uma posição global na scene.
* `raycastSystem.registerTargetEntityRaycast()`: cria um raycast com uma direção definida em direção a uma **entity alvo** posição. O `targetEntity` campo espera uma referência a uma entity; a posição dessa 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, 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.
* `originOffset`: Em vez de iniciar o raycast a partir da posição de origem da entity, adicione um offset para iniciar a query a partir de uma posição relativa. Você pode, por exemplo, usar um pequeno offset para impedir 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 certas collision layers. Use isso junto com uma collision layer personalizada, ou para detectar apenas a layer de physics ou de pointer events. Veja [collision layers](/creator/content-creator-pt/scenes-sdk7/essenciais-de-conteudo-3d/colliders.md#collision-layers). Se não for definido, a layer padrão usada é `ColliderLayer.CL_PHYSICS`.
* `continuous`: Se true, continuará executando uma query de raycast a cada frame. Se false, o ray será usado apenas no frame atual. Se não for definido, o padrão é false.
* 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 global target, o `globalTarget` campo tem como padrão `Vector3.Zero()`.
* Ao definir a direção com um target de entity, o `targetEntity` campo tem como padrão a root entity da scene, localizada em `Vector3.Zero()`.

{% hint style="warning" %}
**📔 Nota**: A `continuous` propriedade deve ser usada com cuidado, pois executar uma query de raycast a cada frame pode ser muito caro para o desempenho. Sempre que possível, use um system (ou a `interval` function na biblioteca Utils) para executar queries de raycast em um intervalo regular mais espaçado, veja [raycasting recorrente](#recurrent-raycasting).
{% endhint %}

Abaixo 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,
      globalTarget: 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"`

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

## Resultado do Raycast

A função callback que trata o raycast recebe um objeto contendo dados sobre o próprio ray e sobre quaisquer entities que foram atingidas.

* `globalOrigin`: A posição de onde o ray foi originado, relativa à scene.
* `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 estará 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 à scene)
* `length`: Comprimento do ray desde sua origem até a posição onde ocorreu o hit contra a entity.
* `normalHit`: *Quaternion* para o ângulo da normal do hit no espaço mundial.
* `globalOrigin`: *Vector3* para a posição onde o ray se origina (relativa à scene)
* `direction`: A direção global para a qual o ray estava apontando, como um `Vector3`.

O exemplo a seguir itera sobre 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('no entities hit')
    }
  }
)
```

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

## Lidar com 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 componentes. Uma entity é [nada mais do que um número](/creator/content-creator-pt/scenes-sdk7/arquitetura/entities-components.md#overview), então o `entityId` valor em si pode ser interpretado como um tipo `Entity` .

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

## Collision layers

É uma boa prática verificar colisões apenas contra entities que sejam relevantes, para tornar a scene mais performática. O `collisionMask` campo permite listar apenas collision layers específicas, que podem incluir a layer de physics (que bloqueia o movimento do player), a layer de pointer (que é usada para pointer events) e 8 layers personalizadas que você pode atribuir livremente conforme suas necessidades. Veja [collision layers](/creator/content-creator-pt/scenes-sdk7/essenciais-de-conteudo-3d/colliders.md#collision-layers). Por padrão, todas as layers são detectadas.

Por padrão, o `collisionMask` campo é definido para responder a ambas as layers `ColliderLayer.CL_POINTER` e `ColliderLayer.CL_PHYSICS`. Você pode alterar esse valor para listar apenas uma delas, ou para incluir layers personalizadas. Use o separador `|` para listar várias opções.

```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`, o comportamento padrão é criar um único ray, que fará a query de colisões uma vez. Como alternativa, você pode definir o `continuous` campo para *true* para executar uma query e a função callback a cada tick do game loop.

O exemplo a seguir continuará executando a query de raycast a partir deste ponto

```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**: A `continuous` propriedade deve ser usada com cuidado, pois executar uma query de raycast a cada frame pode ser muito caro para o desempenho.
{% 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 system (ou a `interval` function na biblioteca Utils) para executar queries de raycast em um intervalo regular mais espaçado, como apenas uma vez por segundo, ou a cada quinto de segundo.

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

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

const RAY_INTERVAL = 0.1

// verificar 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())

// sistema do cubo oscilante
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)
  }
})

// criar cubo
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 cronometrar 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` function 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 isso funciona. Em vez de registrar uma função callback, você pode realizar uma query 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ó ficará disponível no tick seguinte, exigindo duas execuções do system. Uma para registrar o raycast para o próximo frame, e o frame seguinte para processar seu resultado.

```ts
engine.addSystem((deltaTime) => {
		const result = raycastSystem.registerRaycast(
			entity,
			localDirectionOptions({
				collisionMask: ColliderLayer.CL_CUSTOM1 | ColliderLayer.CL_CUSTOM3 | ColliderLayer.CL_POINTER,
				originOffset: Vector3.create(0, 0.4, 0),
				maxDistance: RAY_POWER,
				queryType: raycastQueryType,
				direction: Vector.forward()
				continuous: true // não use em excesso a propriedade 'continuous', pois raycasting é caro para o desempenho
			})
		)
		if (result) // fazer alguma coisa
	})
```

## Colidir com o player

Você não pode atingir diretamente o avatar do player ou o de outros players com um ray, mas o que você pode fazer como alternativa é posicionar uma entity invisível ocupando o mesmo espaço que um player usando o [componente AvatarAttach](/creator/content-creator-pt/scenes-sdk7/essenciais-de-conteudo-3d/entity-positioning.md#attach-an-entity-to-an-avatar), e verificar colisões com esse cubo.

## Raycasts a partir do player

Para traçar um ray a partir da posição do player na direção para a qual a câmera está apontando, você pode traçar um ray usando a câmera ou o avatar [entities reservadas](/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 eveents](/creator/content-creator-pt/scenes-sdk7/interatividade/eventos-de-botao/click-events.md) em vez de raycasts.
{% endhint %}

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

```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**: Lembre-se de que, em 3ª pessoa, o cursor pode, no futuro, não se comportar da mesma forma que em 1ª pessoa. É recomendado usar isso apenas se o player estiver em 1ª pessoa.
{% 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 player para o mundo 3D. Isso pode ser usado para arrastar objetos, shooters etc.

Neste exemplo, detectamos quando o player pressiona a tecla E e então traçamos um ray a partir da posição do cursor para o 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 { EntityNames } from '../assets/scene/entity-names'
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]

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

        // fazer 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 primary (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 câmera por padrão. Se você quiser impedir a rotação da câmera enquanto arrasta, você pode usar um [Virtual Camera](/creator/content-creator-pt/scenes-sdk7/essenciais-de-conteudo-3d/camera.md) para definir o ângulo da câmera como fixo.
{% endhint %}

## Sintaxe avançada

### Criar um componente de raycast

Um componente Raycast descreve o ray invisível usado para consultar entities intersectadas. O ray é traçado a partir da posição da entity, conforme definido pelo componente Transform e afetado por qualquer entity pai. A direção pode ser definida de várias maneiras,

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. A seguir estão os valores aceitos para `$case`:
  * `LOCAL_DIRECTION`: Uma direção relativa à direção frontal da entity, também afetada pela transformação de quaisquer entities pai. Isso é útil para detectar obstáculos à frente de veículos, respeitando seu rumo. A rotação é definida pelo campo `localDirection` , como um `Vector3` que descreve uma rotação.
  * `GLOBAL_DIRECTION`: Ignora a rotação da entity e aponta em uma direção como se a rotação da entity fosse 0. Isso é útil, por exemplo, para sempre apontar para baixo. A rotação é definida pelo `globalDirection` , como um `Vector3` que descreve uma rotação.
  * `GLOBAL_TARGET`: 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 torre de cada torre pode apontar para uma coordenada específica no espaço. O alvo é definido pelo `globalTarget` , como um `Vector3` que descreve a posição global.
  * `TARGET_ENTITY`: Traça uma linha entre a posição da entity e a posição de uma segunda entity alvo. Ignora a rotação de qualquer uma das entities. O alvo é definido pelo `targetEntity` campo, contendo uma referência à entity.
* `maxDistance`: *number* para definir o comprimento com que este ray 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_QUERY_ALL`: retorna apenas a primeira entity atingida, a partir do ponto de origem.
  * `RaycastQueryType.RQT_HIT_FIRST`: retorna todas as entities atingidas, da origem até a distância máxima do ray.
* `collisionMask`: Detecta colisões apenas com certas collision layers. Use isso junto com uma collision layer personalizada, ou para detectar apenas a layer de physics ou de pointer events. Veja [collision layers](/creator/content-creator-pt/scenes-sdk7/essenciais-de-conteudo-3d/colliders.md#collision-layers). Por padrão, todas as layers são detectadas.
* `originOffset`: Em vez de iniciar o raycast a partir da posição de origem da entity, adicione um offset para iniciar a query a partir de uma posição relativa. Você pode, por exemplo, usar um pequeno offset para impedir que o ray colida com o próprio modelo 3D da entity.
* `continuous`: Se true, continuará executando uma query de raycast a cada frame. Se false, o ray será usado apenas no frame atual. Por padrão, esse valor é false.

{% hint style="warning" %}
**📔 Nota**: A `continuous` propriedade deve ser usada com cuidado, pois executar uma query de raycast a cada frame pode ser muito caro para o desempenho. Sempre que possível, use um system (ou a `interval` function na biblioteca Utils) para executar queries 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 ray é 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 ray na direção frontal 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 ray atinja o próprio collider da 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 ray entre duas entities. Ele retorna todas as entities que são atingidas no meio do caminho.

```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 de Raycast

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

Depois de criar um componente Raycast, a entity à qual esse componente foi adicionado terá um `RaycastResult` componente. Esse componente inclui informações sobre quaisquer hits do ray. Configure um system para verificar esses dados.

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

* `globalOrigin`: A posição de onde o ray foi originado, relativa à scene.
* `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 estará 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 à scene)
* `length`: Comprimento do ray desde sua origem até a posição onde ocorreu o hit contra a entity.
* `normalHit`: *Quaternion* para o ângulo da normal do hit no espaço mundial.
* `globalOrigin`: *Vector3* para a posição onde o ray se origina (relativa à scene)
* `direction`: A direção global para a qual o ray estava apontando, como um `Vector3`.

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

```typescript

const rayEntity = engine.addEntity()

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

// retornar todas as 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` componentes de todas as entities na scene, usando uma [consulta de componentes](/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 em que você usa vários tipos de rays para diferentes finalidades (como 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/essenciais-de-conteudo-3d/colliders.md#collision-layers), para evitar calcular colisões irrelevantes.


---

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