> 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-es/escenas-sdk7/interactividad/raycasting.md).

# Raycasting

Raycasting es una herramienta fundamental en el desarrollo de juegos. Con raycasting, puedes trazar una línea imaginaria en el espacio y consultar si alguna Entity es intersectada por esa línea. Esto es útil para calcular líneas de visión, trayectorias de balas, algoritmos de pathfinding y muchas otras aplicaciones.

Cuando un jugador pulsa el botón de Pointer, o el botón primario o secundario, se traza un ray desde la posición del jugador en la dirección en la que está mirando, consulta [eventos de botón](/creator/content-creator-es/escenas-sdk7/interactividad/eventos-de-boton/click-events.md) para más detalles sobre esto. Este documento cubre cómo trazar un ray invisible desde cualquier posición y dirección arbitrarias, independientemente de las acciones del jugador, lo que puedes usar en muchos otros escenarios.

Ten en cuenta que los raycasts solo impactan objetos con colliders. Así que, si quieres detectar impactos de ray contra un modelo 3D, ya sea:

* El modelo debe contener [collider meshes](/creator/content-creator-es/modelado-3d-y-animaciones/colliders.md).
* El `GLTFContainer` debe configurarse para usar la [geometría visible con máscaras de colisión](/creator/content-creator-es/escenas-sdk7/fundamentos-del-contenido-3d/colliders.md#colliders-on-3d-models).
* Añade un [MeshCollider component](/creator/content-creator-es/escenas-sdk7/fundamentos-del-contenido-3d/colliders.md).

También es una buena práctica asignar [capas de colisión](/creator/content-creator-es/escenas-sdk7/fundamentos-del-contenido-3d/colliders.md#collision-layers) a los modelos 3D, para que los rays solo tengan que calcular colisiones contra las entities relevantes, en lugar de contra todo lo que tenga un collider.

## Crear un ray

Todos los rays tienen un punto de origen y una dirección. El punto de origen se basa en la posición de una Entity, tomando los valores del componente Transform de la Entity. La dirección de un ray puede definirse de 4 maneras diferentes:

* **local**: Una dirección relativa a la dirección frontal de la Entity, afectada también por la transformación de cualquier Entity padre. Esto es útil para detectar obstáculos delante de vehículos respetando su rumbo.
* **global**: Ignora la rotación de la Entity y apunta en una dirección como si la rotación de la Entity fuera 0. Esto es útil, por ejemplo, para apuntar siempre hacia abajo.
* **objetivo global**: Traza una línea entre la posición de la Entity y una posición global objetivo en la escena. Ignora la rotación de la Entity. Útil, por ejemplo, para crear juegos de tower defense; la torreta de cada torre puede apuntar a una coordenada precisa en el espacio.
* **Entity objetivo**: Traza una línea entre la posición de la Entity y la posición de una segunda Entity objetivo. Ignora la rotación de cualquiera de las Entities.

El siguiente código crea un raycast con una dirección 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) {
    // función de callback
  }
)
```

Usa las siguientes funciones para crear raycasts proporcionando la dirección de distintas maneras:

* `raycastSystem.registerLocalDirectionRaycast()`: crea un raycast con una **local** dirección. El `direction` campo espera un `Vector3` que describe un vector relativo a la Entity y a su rotación (p. ej. `Vector3.Forward()` terminaría usando el vector forward del Transform de la Entity)
* `raycastSystem.registerGlobalDirectionRaycast()`: crea un raycast con una **global** dirección. El `direction` campo espera un `Vector3` que describe la dirección global.
* `raycastSystem.registerGlobalTargetRaycast()`: crea un raycast con una dirección definida por una **objetivo global** posición. El `target` campo espera un `Vector3` que describe una posición global en la escena.
* `raycastSystem.registerTargetEntityRaycast()`: crea un raycast con una dirección definida hacia una **Entity objetivo** posición. El `targetEntity` campo espera una referencia a una Entity; la posición de esta Entity se usará como objetivo del ray.

Los siguientes campos opcionales están disponibles al crear un ray con cualquiera de los métodos anteriores:

* `maxDistance`: *number* para establecer la longitud con la que se trazará este ray. Si no se establece, el valor predeterminado es 16 metros.
* `queryType`: *RaycastQueryType* valor del enum para definir si el ray devolverá todas las Entities impactadas o solo la primera. Las siguientes opciones están disponibles:
  * `RaycastQueryType.RQT_HIT_FIRST`: *(predeterminado)* solo devuelve la primera Entity impactada, empezando desde el punto de origen.
  * `RaycastQueryType.RQT_QUERY_ALL`: devuelve todas las Entities impactadas, desde el origen hasta la distancia máxima del ray.
* `originOffset`: En lugar de empezar el raycast desde la posición de origen de la Entity, añade un desplazamiento para iniciar la consulta desde una posición relativa. Por ejemplo, puedes usar un pequeño desplazamiento para evitar que el ray colisione con el propio collider de la Entity. Si no se establece, el valor predeterminado es `Vector3.Zero()`.
* `collisionMask`: Detecta colisiones solo con ciertas capas de colisión. Úsalo junto con una capa de colisión personalizada, o para detectar solo la capa de physics o la de pointer events. Consulta [capas de colisión](/creator/content-creator-es/escenas-sdk7/fundamentos-del-contenido-3d/colliders.md#collision-layers). Si no se establece, la capa predeterminada usada es `ColliderLayer.CL_PHYSICS`.
* `continuous`: Si es true, seguirá ejecutando una consulta de raycast en cada frame. Si es false, el ray solo se usará en el frame actual. Si no se establece, el valor predeterminado es false.
* Al establecer la dirección con una dirección local o glocal, el `direction` campo tiene como valor predeterminado `Vector3.Forward()`.
* Al establecer la dirección con un objetivo global, el `target` campo tiene como valor predeterminado `Vector3.Zero()`.
* Al establecer la dirección con un objetivo de Entity, el `targetEntity` campo tiene como valor predeterminado la Entity raíz de la escena, ubicada en `Vector3.Zero()`.

{% hint style="warning" %}
**📔 Nota**: El `continuous` propiedad debe usarse con precaución, ya que ejecutar una consulta de raycast en cada frame puede ser muy costoso para el rendimiento. Cuando sea posible, usa un System (o la `interval` función de la librería Utils) para ejecutar consultas de raycast a intervalos regulares más espaciados, consulta [raycasting recurrente](#recurrent-raycasting).
{% endhint %}

A continuación se muestran ejemplos usando cada uno de los cuatro métodos para determinar la dirección del ray:

```ts
// RAYCAST DE DIRECCIÓN LOCAL
raycastSystem.registerLocalDirectionRaycast(
  {
    entity: myEntity,
    opts: {
      queryType: RaycastQueryType.RQT_QUERY_ALL,
      direction: Vector3.Forward(),
      maxDistance: 30,
    },
  },
  function (raycastResult) {
    console.log(raycastResult.hits)
  }
)
// RAYCAST DE DIRECCIÓN GLOBAL
raycastSystem.registerGlobalDirectionRaycast(
  {
    entity: myEntity,
    opts: {
      queryType: RaycastQueryType.RQT_QUERY_ALL,
      direction: Vector3.Forward(),
      maxDistance: 30,
    },
  },
  function (raycastResult) {
    console.log(raycastResult.hits)
  }
)
// RAYCAST DE POSICIÓN OBJETIVO GLOBAL
raycastSystem.registerGlobalTargetRaycast(
  {
    entity: myEntity,
    opts: {
      queryType: RaycastQueryType.RQT_QUERY_ALL,
      target: Vector3.Zero(),
    },
  },
  (raycastResult) => {
    console.log(raycastResult.hits)
  }
)
// RAYCAST DE ENTITY OBJETIVO
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` y `ColliderLayer` debe importarse mediante

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

Consulta [Importaciones](/creator/content-creator-es/escenas-sdk7/primeros-pasos/coding-scenes.md#imports) para saber cómo manejarlos fácilmente.
{% endhint %}

## Resultado del raycast

La función de callback que maneja el raycast recibe un objeto que contiene datos sobre el propio ray y cualquier Entity que haya sido impactada.

* `globalOrigin`: La posición donde se originó el ray, relativa a la escena.
* `direction`: La dirección global hacia la que apuntaba el ray, como un `Vector3`.
* `hits`: Un array con un objeto por cada Entity que fue impactada. Si no hubo Entities impactadas, este array está vacío. Si el raycast usó `RaycastQueryType.RQT_HIT_FIRST`, este array solo contendrá un objeto.

Cada objeto del `hits` array incluye:

* `entityId`: Número de Id de la Entity que fue impactada por el ray.
* `meshName`: *String* con el nombre interno del mesh específico del modelo 3D que fue impactado. Esto es útil cuando un modelo 3D está compuesto por múltiples meshes.
* `position`: *Vector3* de la posición donde el ray intersectó con la Entity impactada (relativa a la escena)
* `length`: Longitud del ray desde su origen hasta la posición donde ocurrió el impacto contra la Entity.
* `normalHit`: *Vector3* de la normal de la superficie impactada en world space.
* `globalOrigin`: *Vector3* de la posición donde se origina el ray (relativa a la escena)
* `direction`: La dirección global hacia la que apuntaba el ray, como un `Vector3`.

El siguiente ejemplo itera sobre las Entities que fueron impactadas:

```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('Entity impactada ', hit.entityId)
        }
      }
    } else {
      console.log('no se impactó ninguna Entity')
    }
  }
)
```

{% hint style="warning" %}
**📔 Nota**: Puedes obtener un resultado de raycast al impactar una Entity en una escena diferente.
{% endhint %}

## Manejar Entities impactadas

Cuando obtienes un resultado de raycast que impactó una Entity, puedes usar el `entityId` para interactuar con la Entity y sus Components. Una Entity es [nada más que un número](/creator/content-creator-es/escenas-sdk7/arquitectura/entities-components.md#overview), así que el `entityId` valor en sí puede interpretarse como un `Entity` tipo.

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

## Capas de colisión

Es una buena práctica comprobar colisiones solo contra Entities relevantes, para hacer la escena más eficiente. El `collisionMask` campo te permite listar solo capas de colisión específicas: la capa de physics (paredes y suelos de la escena), la capa de Pointer (pointer events), las capas de player (avatars), o 8 capas personalizadas que puedes asignar libremente. Consulta [capas de colisión](/creator/content-creator-es/escenas-sdk7/fundamentos-del-contenido-3d/colliders.md#collision-layers).

Por defecto, el `collisionMask` campo está establecido en `ColliderLayer.CL_PHYSICS`. Puedes cambiar este valor para listar otras capas, o combinar varias con el `|` 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 recurrente

Al usar las funciones de `raycastSystem`, el comportamiento predeterminado es crear un solo ray, que consultará colisiones una vez. Como alternativa, puedes establecer el `continuous` campo en *true* para ejecutar una consulta y la función de callback en cada tick del game loop.

El siguiente ejemplo seguirá ejecutando la consulta de raycast a partir de este punto

```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**: El `continuous` propiedad debe usarse con precaución, ya que ejecutar una consulta de raycast en cada frame puede ser muy costoso para el rendimiento.
{% endhint %}

Cuando ya no sea necesario, elimina cualquier raycast recurrente. Para hacerlo, debes usar `raycastSystem.removeRaycasterEntity`.

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

Cuando sea posible, usa un System (o la `interval` función en la librería Utils) para ejecutar consultas de raycast a intervalos regulares más espaciados, como una vez por segundo o 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

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

// system de 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)
  }
})

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

El ejemplo anterior ejecuta un raycast recurrente cada 0.1 segundos. Usa un componente de temporizador y la `dt` propiedad para temporizarlos de forma uniforme. También incluye un cubo que oscila hacia arriba y hacia abajo, controlado por otro System, para entrar y salir de la trayectoria del ray.

{% hint style="info" %}
**💡 Consejo**: Usa la `interval` función de la [librería SDK Utils](https://github.com/decentraland/sdk7-utils) para una forma más sencilla de ejecutar una función a un intervalo fijo.
{% endhint %}

## Raycasts mediante un System

Otra forma de realizar raycasts recurrentes es ejecutarlos desde la función recurrente de un System. Esto te permite tener mucho más control sobre cuándo y cómo funcionan. En lugar de registrar una función de callback, puedes realizar una consulta de raycast con `raycastSystem.registerRaycast` y luego comprobar los datos devueltos por esta operación, todo dentro de la función del System.

Ten en cuenta que, como el raycast se ejecuta en un System, el resultado solo estará disponible en el siguiente tick, por lo que se necesitan dos ejecuciones del System: una para registrar el raycast para el siguiente frame y la siguiente para procesar su 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 // no abuses de la propiedad 'continuous' ya que raycasting es costoso para el rendimiento
			})
		)
		if (result) {
			// hacer algo
		}
	})
```

## Colisionar con el jugador

Puedes detectar avatars directamente con raycasts incluyendo cualquiera de las capas de colisión de avatar en la máscara:

* `ColliderLayer.CL_PLAYER`: coincide con cualquier avatar — el jugador local Y cualquier otro jugador renderizado en la escena.
* `ColliderLayer.CL_MAIN_PLAYER`: coincide solo con el jugador local (main).

Ambas capas pueden combinarse o usarse de forma independiente. El `collisionMask` predeterminado para un raycast es `CL_PHYSICS`, que NO impacta avatars — debes habilitarlo explícitamente.

```ts
// Impacta solo al jugador local (ignora otros avatars)
raycastSystem.registerLocalDirectionRaycast(
  {
    entity: myEntity,
    opts: {
      direction: Vector3.Forward(),
      collisionMask: ColliderLayer.CL_MAIN_PLAYER,
    },
  },
  (raycastResult) => {
    if (raycastResult.hits.length > 0) {
      console.log('Ha impactado al jugador local')
    }
  }
)

// Impacta cualquier avatar (local + remoto)
raycastSystem.registerLocalDirectionRaycast(
  {
    entity: myEntity,
    opts: {
      direction: Vector3.Forward(),
      collisionMask: ColliderLayer.CL_PLAYER,
    },
  },
  (raycastResult) => {
    // raycastResult.hits[i].entityId es 0 para impactos en avatars remotos (sin id de Entity local de la escena)
    console.log(raycastResult.hits)
  }
)
```

Cuando un raycast impacta al jugador local, el `hit.entityId` es `engine.PlayerEntity`. Los impactos en avatars remotos no llevan un id de Entity local de la escena (el campo es `0`) ya que el jugador remoto no es una Entity en el mundo de tu escena — pero el impacto sigue reportándose con su `position`, `length`, `normalHit`, y otros datos geométricos.

{% hint style="info" %}
**💡 Consejo**: Para detectar solo **otros** jugadores (excluyendo al jugador local), usa `CL_PLAYER` y filtra `hit.entityId !== engine.PlayerEntity` en el callback.
{% endhint %}

## Raycasts desde el jugador

Para trazar un ray desde la posición del jugador en la dirección hacia la que mira la cámara, puedes trazar un ray usando la cámara o el avatar [Entities reservadas](/creator/content-creator-es/escenas-sdk7/arquitectura/entities-components.md#reserved-entities).

{% hint style="info" %}
**💡 Consejo**: En la mayoría de los casos, quizás te convenga más usar [Eventos de Pointer](/creator/content-creator-es/escenas-sdk7/interactividad/eventos-de-boton/click-events.md) en lugar de raycasts.
{% endhint %}

El siguiente ejemplo traza un ray desde la posición de la cámara del jugador hacia delante, usando la `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**: Ten en cuenta que en tercera persona el cursor podría en el futuro no comportarse igual que en primera persona. Se recomienda usar esto solo si el jugador está en primera persona.
{% endhint %}

## Raycast desde la posición del cursor

También puedes trazar un ray desde la posición del cursor del jugador hacia el mundo 3D. Esto puede usarse para arrastrar objetos, shooters, etc.

En este ejemplo, detectamos cuándo el jugador presiona la tecla E, y luego trazamos un ray desde la posición del cursor hacia el mundo 3D. Después comprobamos si el ray impactó alguna Entity y, si es así, hacemos algo con ella.

```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]

        // hacer algo en la posición de impacto
        if (result && result.position) {
          console.log("x:", result.position.x, ", y:", result.position.y, ", z:", result.position.z)
        }

        // hacer algo con la entidad impactada
        const entity = result.entityId as Entity
        if (entity) {
          console.log("entity: ", entity)
        }
      }
    )
}

```

{% hint style="info" %}
**💡 Consejo**: En este ejemplo usamos el botón principal (E) para activar el raycast. No usamos el botón del pointer (clic izquierdo) porque al hacer clic y arrastrar también se cambia el ángulo de la cámara por defecto. Si quieres evitar rotar la cámara mientras arrastras, puedes usar una [Virtual Camera](/creator/content-creator-es/escenas-sdk7/fundamentos-del-contenido-3d/camera.md) para establecer el ángulo de la cámara como fijo.
{% endhint %}

## Sintaxis avanzada

### Crear un componente Raycast

Un componente Raycast describe el rayo invisible que se usa para consultar entidades intersectadas. El rayo se traza comenzando en la posición de la entidad, tal como la define el componente Transform y afectado por la de cualquier entidad padre. La dirección puede definirse de varias maneras,

Los rayos se definen usando los siguientes datos:

* `direction`: Un objeto que contiene un `$case` campo para seleccionar el tipo de dirección, y un campo adicional que dependerá de este tipo, que determina esta dirección. Los siguientes son los valores aceptados para `$case`:
  * `'localDirection'`: Una dirección relativa a la dirección frontal de la entidad, también afectada por la transformación de cualquier entidad padre. Esto es útil para detectar obstáculos delante de vehículos respetando su rumbo. La rotación se define por el `localDirection` campo, como un `Vector3` que describe una rotación.
  * `'globalDirection'`: Ignora la rotación de la entidad y apunta en una dirección como si la rotación de la entidad fuera 0. Esto es útil para, por ejemplo, apuntar siempre hacia abajo. La rotación se define por el `globalDirection` campo, como un `Vector3` que describe una rotación.
  * `'globalTarget'`: Traza una línea entre la posición de la entidad y una posición global objetivo en la escena. Ignora la rotación de la entidad. Útil para crear juegos de tower defense: la torreta de cada torre puede apuntar a una coordenada precisa en el espacio. El objetivo se define por el `globalTarget` campo, como un `Vector3` que describe la posición global.
  * `'targetEntity'`: Traza una línea entre la posición de la entidad y la posición de una segunda entidad objetivo. Ignora la rotación de cualquiera de las entidades. El objetivo se define por el `targetEntity` campo, que contiene una referencia a la entidad.
* `maxDistance`: *number* para establecer la longitud con la que se trazará este rayo.
* `queryType`: *RaycastQueryType* valor del enum para definir si el ray devolverá todas las Entities impactadas o solo la primera. Las siguientes opciones están disponibles:
  * `RaycastQueryType.RQT_HIT_FIRST`: solo devuelve la primera entidad impactada, comenzando desde el punto de origen.
  * `RaycastQueryType.RQT_QUERY_ALL`: devuelve todas las Entities impactadas, desde el origen hasta la distancia máxima del ray.
* `collisionMask`: Detecta colisiones solo con ciertas capas de colisión. Úsalo junto con una capa de colisión personalizada, o para detectar solo la capa de physics o la de pointer events. Consulta [capas de colisión](/creator/content-creator-es/escenas-sdk7/fundamentos-del-contenido-3d/colliders.md#collision-layers). Por defecto, el valor es `ColliderLayer.CL_POINTER | ColliderLayer.CL_PHYSICS`.
* `originOffset`: En lugar de iniciar el raycast desde la posición de origen de la entidad, añade un desplazamiento para comenzar la consulta desde una posición relativa. Por ejemplo, puedes usar un pequeño desplazamiento para evitar que el rayo colisione con el propio modelo 3D de la entidad.
* `continuous`: Si es true, seguirá ejecutando una consulta raycast en cada frame. Si es false, el rayo solo se usará en el frame actual. Por defecto, este valor es false.

{% hint style="warning" %}
**📔 Nota**: El `continuous` propiedad debe usarse con precaución, ya que ejecutar una consulta de raycast en cada frame puede ser muy costoso para el rendimiento. Cuando sea posible, usa un System (o la `interval` función de la librería Utils) para ejecutar consultas de raycast a intervalos regulares más espaciados, consulta [raycasting recurrente](#recurrent-raycasting).
{% endhint %}

El siguiente ejemplo usa una rotación global para determinar la dirección, y solo devuelve la primera entidad que es impactada en el frame en que se envía el rayo.

```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
})
```

El siguiente ejemplo lanza un rayo en la dirección frontal de la entidad, devolviendo solo el primer elemento impactado. Lo hace de forma continua. También incluye un pequeño desplazamiento de 0.5 para evitar que el rayo golpee el collider de la propia entidad.

```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 ejemplo traza un rayo entre dos entidades. Devuelve todas las entidades que son impactadas entre ellas.

```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**: La forma más fácil de trabajar con los resultados de raycast es usar `raycastSystem`, y registrar una función callback como parte de la misma instrucción que crea el rayo. El`RaycastResult` componente se usa internamente por esa interfaz, pero también se expone para habilitar lógica personalizada más avanzada.
{% endhint %}

Después de crear un componente Raycast, la entidad a la que se agrega este componente tendrá un `RaycastResult` componente. Este componente incluye información sobre cualquier impacto del rayo. Configura un System para comprobar estos datos.

El `RaycastResult` componente contiene los siguientes datos:

* `globalOrigin`: La posición donde se originó el ray, relativa a la escena.
* `direction`: La dirección global hacia la que apuntaba el ray, como un `Vector3`.
* `hits`: Un array con un objeto por cada Entity que fue impactada. Si no hubo Entities impactadas, este array está vacío. Si el raycast usó `RaycastQueryType.RQT_HIT_FIRST`, este array solo contendrá un objeto.

Cada objeto del `hits` array incluye:

* `entityId`: Número de Id de la Entity que fue impactada por el ray.
* `meshName`: *String* con el nombre interno del mesh específico del modelo 3D que fue impactado. Esto es útil cuando un modelo 3D está compuesto por múltiples meshes.
* `position`: *Vector3* de la posición donde el ray intersectó con la Entity impactada (relativa a la escena)
* `length`: Longitud del ray desde su origen hasta la posición donde ocurrió el impacto contra la Entity.
* `normalHit`: *Vector3* de la normal de la superficie impactada en world space.
* `globalOrigin`: *Vector3* de la posición donde se origina el ray (relativa a la escena)
* `direction`: La dirección global hacia la que apuntaba el ray, como un `Vector3`.

El siguiente ejemplo muestra cómo puedes acceder a los resultados de una entidad individual usando un System:

```typescript

const rayEntity = engine.addEntity()

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

// devolver todas las entidades
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)
})
```

El siguiente ejemplo muestra cómo puedes acceder a `RaycastResult` componentes de todas las entidades de la escena, usando una [consulta de componentes](/creator/content-creator-es/escenas-sdk7/arquitectura/querying-components.md).

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

{% hint style="warning" %}
**📔 Nota**: Los resultados de un raycast no llegan en el mismo tick del game loop en el que creaste el raycast. Los resultados pueden tardar uno o varios ticks en llegar.
{% endhint %}

En una Scene en la que uses varios tipos de rayos para distintos propósitos (como para búsqueda de rutas, comprobación de línea de visión, trazado de proyectiles, etc.), quizá quieras usar diferentes [capas de colisión](/creator/content-creator-es/escenas-sdk7/fundamentos-del-contenido-3d/colliders.md#collision-layers), para evitar calcular colisiones irrelevantes.

{% hint style="info" %}
**💡 Consejo**: Para ver un ejemplo funcional de raycasting, consulta la [`77,-1-raycast-unit-tests`](https://github.com/decentraland/sdk7-test-scenes/tree/main/scenes/77,-1-raycast-unit-tests) test scene, que valida el comportamiento del raycast mediante `@dcl/sdk/testing` unit tests en las `localDirection`, `globalDirection`, `globalTarget` y `targetEntity` formas de dirección, incluidos los rayos lanzados desde entidades padre transformadas. Para ver cómo se comportan las capas de Collider que puede golpear un rayo, consulta [`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-es/escenas-sdk7/interactividad/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.
