> 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 projéteis, 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 raio é traçado a partir 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/eventos-de-botao/click-events.md) para mais detalhes sobre isso. Este documento aborda como traçar um raio invisível a partir de qualquer posição e direção arbitrárias, independentemente das ações do jogador, que você pode usar em muitos outros cenários.

Observe que os raycasts só atingem objetos com colliders. Portanto, se você quiser detectar impactos de raycast contra um modelo 3D, faça uma das opções abaixo:

* O modelo deve conter [malhas de colisão](/creator/content-creator-pt/modelacao-3d-e-animacoes/colliders.md).
* O `GLTFContainer` deve ser configurado para usar a [geometria visível com máscaras de colisão](/creator/content-creator-pt/scenes-sdk7/fundamentos-de-conteudo-3d/colliders.md#colliders-on-3d-models).
* Adicione um [MeshCollider component](/creator/content-creator-pt/scenes-sdk7/fundamentos-de-conteudo-3d/colliders.md).

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

## Criar um raio

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

* **locais**: 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 sempre apontar para baixo.
* **alvo global**: Traça uma linha entre a posição da Entity e uma posição global de destino na scene. Ignora a rotação da Entity. Útil, por exemplo, para criar jogos tower defense, em que a torreta de cada torre pode apontar para uma coordenada exata 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 callback
  }
)
```

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

* `raycastSystem.registerLocalDirectionRaycast()`: cria um raycast com uma **locais** direção local. O `direção` 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 local. O `direção` 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 `alvo` 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 raio.

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

* `maxDistance`: *number* para definir o comprimento com que esse raio será traçado. Se não for definido, o padrão é 16 metros.
* `queryType`: *RaycastQueryType* valor enum, para definir se o raio 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 raio.
* `originOffset`: Em vez de iniciar o raycast na posição de origem da Entity, adicione um deslocamento para iniciar a consulta a partir de uma posição relativa. Por exemplo, você pode usar um pequeno deslocamento para impedir que o raio 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 layers de colisão. Use isso em conjunto com uma layer de colisão personalizada, ou para detectar apenas a layer de physics ou de pointer events. Veja [camadas de colisão](/creator/content-creator-pt/scenes-sdk7/fundamentos-de-conteudo-3d/colliders.md#collision-layers). Se não for definido, a layer padrão usada é `ColliderLayer.CL_PHYSICS`.
* `contínuo`: Se for true, continuará executando uma consulta de raycast a cada frame. Se for false, o raio 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 global, o `direção` campo assume como padrão `Vector3.Forward()`.
* Ao definir a direção com um alvo global, o `alvo` campo assume como padrão `Vector3.Zero()`.
* Ao definir a direção com uma Entity alvo, o `targetEntity` campo assume como padrão a root entity da scene, localizada em `Vector3.Zero()`.

{% hint style="warning" %}
**📔 Observação**: A `contínuo` propriedade deve ser usada com cautela, pois executar uma consulta de raycast a cada frame pode ser muito pesado para o desempenho. Quando possível, use um system (ou a `interval` função da biblioteca Utils) para executar consultas de raycast em um intervalo mais esparso e regular, veja [raycasting recorrente](#recurrent-raycasting).
{% endhint %}

Abaixo estão exemplos usando cada um dos quatro métodos para determinar a direção do raio:

```ts
// RAYCAST DE DIREÇÃO LOCAL
raycastSystem.registerLocalDirectionRaycast(
  {
    entity: myEntity,
    opts: {
      queryType: RaycastQueryType.RQT_QUERY_ALL,
      direction: Vector3.Forward(),
      maxDistance: 30,
    },
  },
  function (raycastResult) {
    console.log(raycastResult.hits)
  }
)
// RAYCAST DE DIREÇÃO GLOBAL
raycastSystem.registerGlobalDirectionRaycast(
  {
    entity: myEntity,
    opts: {
      queryType: RaycastQueryType.RQT_QUERY_ALL,
      direction: Vector3.Forward(),
      maxDistance: 30,
    },
  },
  function (raycastResult) {
    console.log(raycastResult.hits)
  }
)
// RAYCAST DE POSIÇÃO DE ALVO GLOBAL
raycastSystem.registerGlobalTargetRaycast(
  {
    entity: myEntity,
    opts: {
      queryType: RaycastQueryType.RQT_QUERY_ALL,
      target: Vector3.Zero(),
    },
  },
  (raycastResult) => {
    console.log(raycastResult.hits)
  }
)
// RAYCAST DE ENTITY ALVO
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" %}
**📔 Observação**: `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 com isso facilmente.
{% endhint %}

## Resultado do raycast

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

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

Cada objeto no `hits` array inclui:

* `entityId`: Número de identificação da Entity que foi atingida pelo raio.
* `meshName`: *String* com o nome interno da malha específica no modelo 3D que foi atingida. Isso é útil quando um modelo 3D é composto por várias malhas.
* `position`: *Vector3* para a posição onde o raio se intersectou com a Entity atingida (relativa à scene)
* `length`: Comprimento do raio desde sua origem até a posição em que ocorreu o impacto contra a Entity.
* `normalHit`: *Vector3* para a normal da superfície atingida no espaço mundial.
* `globalOrigin`: *Vector3* para a posição de onde o raio se origina (relativa à scene)
* `direção`: A direção global para a qual o raio 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('no entities hit')
    }
  }
)
```

{% hint style="warning" %}
**📔 Observação**: Você pode obter um resultado de raycast ao atingir uma Entity em uma scene 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), portanto o `entityId` próprio valor pode ser interpretado como um tipo `Entity` .

```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 scene mais performática. O `collisionMask` campo permite listar apenas layers de colisão específicas — a layer de physics (paredes e pisos da scene), a layer de pointer (pointer events), as layers de jogador (avatares), ou 8 layers personalizadas que você pode atribuir livremente. Veja [camadas de colisão](/creator/content-creator-pt/scenes-sdk7/fundamentos-de-conteudo-3d/colliders.md#collision-layers).

Por padrão, o `collisionMask` campo é definido como `ColliderLayer.CL_PHYSICS`. Você pode alterar esse valor para listar outras layers, 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`, o comportamento padrão é criar um único raio, que consultará colisões uma vez. Como alternativa, você pode definir o `contínuo` campo como *true* para executar uma consulta e a função callback a cada tick do game loop.

O exemplo a seguir continuará executando a consulta 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" %}
**📔 Observação**: A `contínuo` propriedade deve ser usada com cautela, pois executar uma consulta de raycast a cada frame pode ser muito pesado para o desempenho.
{% endhint %}

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

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

Quando possível, use um system (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
// components personalizados
const CubeOscilator = engine.defineComponent('CubeOscilator', {
  t: Schemas.Float,
})

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

const RAY_INTERVAL = 0.1

// verificar raios
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 cronometrar isso de forma uniforme. Ele também inclui um cube que oscila para cima e para baixo, controlado por outro system, para entrar e sair do caminho do raio.

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

## Raycasts via um system

Outra maneira de realizar raycasts recorrentes é executá-los a partir 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 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 próximo frame, e a próxima para processar o 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 abuse da propriedade 'continuous', pois raycasting é pesado para o desempenho
			})
		)
		if (result) {
			// faça algo
		}
	})
```

## Colidir com o jogador

Você pode detectar avatares diretamente com raycasts incluindo qualquer uma das layers de colisão de avatar na máscara:

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

Ambas as layers podem ser combinadas ou usadas de forma independente. O `collisionMask` padrão para um raycast é `CL_PHYSICS`, que NÃO atinge avatares — você precisa optar explicitamente.

```ts
// Atinge apenas o jogador local (ignora outros avatares)
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')
    }
  }
)

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

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

{% hint style="info" %}
**💡 Dica**: Para detectar apenas **outros** jogadores (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 raio a partir da posição do jogador na direção para a qual a câmera está voltada, você pode traçar um raio usando a câmera ou o avatar [Entidades 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 events](/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 raio da posição da câmera do jogador para frente, usando a entidade `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" %}
**📔 Observação**: Tenha em mente que, em 3ª pessoa, o cursor pode no futuro não se comportar da mesma forma que em 1ª pessoa. Recomenda-se usar isso apenas se o jogador estiver em 1ª pessoa.
{% endhint %}

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

Você também pode traçar um raio a partir da posição do cursor do jogador para o 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 raio a partir da posição do cursor para o mundo 3D. Em seguida, verificamos se o raio 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 primário (E) para acionar 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/fundamentos-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 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 raios são definidos usando os seguintes dados:

* `direção`: Um objeto que contém um `$case` campo para selecionar o tipo de direção e um campo adicional que dependerá desse tipo, e que determina essa direção. Os seguintes valores são aceitos para `$case`:
  * `'localDirection'`: 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. A rotação é definida pelo `localDirection` campo, como um `Vector3` que descreve uma rotação.
  * `'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 sempre apontar para baixo. A rotação é definida pelo `globalDirection` campo, como um `Vector3` que descreve uma rotação.
  * `'globalTarget'`: Traça uma linha entre a posição da Entity e uma posição global de destino na scene. Ignora a rotação da Entity. Útil para criar jogos tower defense, em que a torreta de cada torre pode apontar para uma coordenada exata no espaço. O alvo é definido pelo `globalTarget` campo, como um `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 esse raio será traçado.
* `queryType`: *RaycastQueryType* valor enum, para definir se o raio 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 raio.
* `collisionMask`: Detecta colisões apenas com certas layers de colisão. Use isso em conjunto com uma layer de colisão personalizada, ou para detectar apenas a layer de physics ou de pointer events. Veja [camadas de colisão](/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 na posição de origem da Entity, adicione um deslocamento para iniciar a consulta a partir de uma posição relativa. Por exemplo, você pode usar um pequeno deslocamento para impedir que o raio colida com o próprio modelo 3D da Entity.
* `contínuo`: Se true, manterá a execução de uma consulta de raycast em cada frame. Se false, o raio será usado apenas no frame atual. Por padrão, esse valor é false.

{% hint style="warning" %}
**📔 Observação**: A `contínuo` propriedade deve ser usada com cautela, pois executar uma consulta de raycast a cada frame pode ser muito pesado para o desempenho. Quando possível, use um system (ou a `interval` função da biblioteca Utils) para executar consultas de raycast em um intervalo mais esparso e regular, 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 é lançado.

```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 voltada para a frente da Entity, retornando apenas o primeiro item atingido. Ele faz isso continuamente. Também inclui um pequeno deslocamento 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
})
```

### component de resultados de Raycast

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

Depois de criar um component Raycast, a Entity à qual esse component é adicionado terá um `RaycastResult` component. Esse 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 de onde o raio foi originado, relativa à scene.
* `direção`: A direção global para a qual o raio estava apontando, como um `Vector3`.
* `hits`: Um array com um objeto para cada Entity que foi atingida. Se não houver Entities atingidas, esse array fica vazio. Se o raycast usou `RaycastQueryType.RQT_HIT_FIRST`, esse array conterá apenas um objeto.

Cada objeto no `hits` array inclui:

* `entityId`: Número de identificação da Entity que foi atingida pelo raio.
* `meshName`: *String* com o nome interno da malha específica no modelo 3D que foi atingida. Isso é útil quando um modelo 3D é composto por várias malhas.
* `position`: *Vector3* para a posição onde o raio se intersectou com a Entity atingida (relativa à scene)
* `length`: Comprimento do raio desde sua origem até a posição em que ocorreu o impacto contra a Entity.
* `normalHit`: *Vector3* para a normal da superfície atingida no espaço mundial.
* `globalOrigin`: *Vector3* para a posição de onde o raio se origina (relativa à scene)
* `direção`: A direção global para a qual o raio estava apontando, como um `Vector3`.

O exemplo abaixo mostra como você pode aceder a resultados de uma Entity individual usando um system:

```typescript

const rayEntity = engine.addEntity()

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

// retorna 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 aceder a `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" %}
**📔 Observação**: Os resultados de um raycast não chegam no mesmo tick do game loop em que você criou o raycast. Os resultados podem demorar um ou vários ticks a chegar.
{% endhint %}

Numa scene em que você usa vários tipos de raios para diferentes propósitos (como para busca de caminho, verificação de line-of-sight, rastreamento de projéteis, etc.), talvez você queira usar diferentes [camadas de colisão](/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 um exemplo funcional de raycasting, veja a [`77,-1-raycast-unit-tests`](https://github.com/decentraland/sdk7-test-scenes/tree/main/scenes/77,-1-raycast-unit-tests) test scene, que confirma o comportamento do raycast através de `@dcl/sdk/testing` unit tests 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 as collider layers que um raio 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 by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.decentraland.org/creator/content-creator-pt/scenes-sdk7/interatividade/raycasting.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

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.
