> 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

El 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 entidad 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 presiona el botón del puntero, o el botón primario o secundario, se traza un rayo desde la posición del jugador en la dirección en la que está mirando, ver [eventos de botones](/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 rayo invisible desde cualquier posición y dirección arbitrarias, independientemente de las acciones del jugador, lo cual puedes usar en muchos otros escenarios.

Ten en cuenta que los raycasts solo impactan objetos con colliders. Así que, si quieres detectar impactos de rayos contra un modelo 3D, debes hacer una de estas cosas:

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

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

## Crear un rayo

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

* **local**: Una dirección relativa a la dirección frontal de la entidad, afectada también por la transformación de cualquier entidad padre. Esto es útil para detectar obstáculos delante de vehículos respetando su rumbo.
* **global**: 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, por ejemplo, para apuntar siempre hacia abajo.
* **objetivo global**: 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, por ejemplo, para crear juegos de tower defense; la torreta de cada torre puede apuntar a una coordenada exacta en el espacio.
* **entidad objetivo**: 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 dos entidades.

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 entidad y a su rotación (por ejemplo, `Vector3.Forward()` terminaría usando el vector frontal del Transform de la entidad)
* `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 **entidad objetivo** posición. El `targetEntity` campo espera una referencia a una entidad; la posición de esta entidad se usará como el objetivo del rayo.

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

* `maxDistance`: *number* para establecer la longitud con la que se trazará este rayo. Si no se establece, el valor predeterminado es 16 metros.
* `queryType`: *RaycastQueryType* valor enum, para definir si el rayo devolverá todas las entidades impactadas o solo la primera. Las siguientes opciones están disponibles:
  * `RaycastQueryType.RQT_HIT_FIRST`: *(predeterminado)* solo devuelve la primera entidad impactada, comenzando desde el punto de origen.
  * `RaycastQueryType.RQT_QUERY_ALL`: devuelve todas las entidades impactadas, desde el origen hasta la distancia máxima del rayo.
* `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 collider de la entidad. Si no se establece, el valor predeterminado es `Vector3.Zero()`.
* `collisionMask`: Detecta solo colisiones con ciertas capas de colisión. Usa esto junto con una capa de colisión personalizada, o para detectar solo la capa de física o la de pointer events. Ver [capas de colisión](/creator/content-creator-es/escenas-sdk7/conceptos-basicos-de-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 rayo solo se usará en el frame actual. Si no se establece, el valor predeterminado es false.
* Cuando se establece la dirección con una dirección local o global, el `direction` campo tiene como valor predeterminado `Vector3.Forward()`.
* Cuando se establece la dirección con un objetivo global, el `target` campo tiene como valor predeterminado `Vector3.Zero()`.
* Cuando se establece la dirección con una entidad objetivo, el `targetEntity` campo tiene como valor predeterminado la entidad raíz de la escena, ubicada en `Vector3.Zero()`.

{% hint style="warning" %}
**📔 Nota**: La `continuous` propiedad debe usarse con cautela, 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 un intervalo regular más espaciado, ver [raycasting recurrente](#recurrent-raycasting).
{% endhint %}

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

```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 ENTIDAD 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` deben importarse mediante

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

Consulta [Imports](/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 rayo y sobre cualquier entidad que haya sido impactada.

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

Cada objeto en el `hits` arreglo incluye:

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

El siguiente ejemplo recorre las entidades 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('entidad impactada ', hit.entityId)
        }
      }
    } else {
      console.log('ninguna entidad impactada')
    }
  }
)
```

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

## Manejar entidades impactadas

Cuando obtienes un resultado de raycast que impactó una entidad, puedes usar el `entityId` para interactuar con la entidad y sus componentes. Una entidad 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 solo las colisiones contra entidades que sean relevantes, para hacer la escena más eficiente. El `collisionMask` campo te permite listar solo capas de colisión específicas — la capa de física (paredes y suelos de la escena), la capa de pointer (pointer events), las capas de jugador (avatares), u 8 capas personalizadas que puedes asignar libremente. Ver [capas de colisión](/creator/content-creator-es/escenas-sdk7/conceptos-basicos-de-contenido-3d/colliders.md#collision-layers).

De forma predeterminada, 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

Cuando uses las funciones de la `raycastSystem`, el comportamiento predeterminado es crear un solo rayo, que consultará colisiones una vez. Como alternativa, puedes establecer el `continuous` campo a *true* para ejecutar una consulta y la función de callback en cada tick del bucle del juego.

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

Cuando ya no lo necesites, 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 de la librería Utils) para ejecutar consultas de raycast a intervalos regulares más espaciados, como solo una vez por segundo, o cada quinta parte de segundo.

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

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

const RAY_INTERVAL = 0.1

// comprobar rayos
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 del 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 temporizador y la `dt` propiedad del System 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 del camino del rayo.

{% hint style="info" %}
**💡 Consejo**: Usa la `interval` función en la [librería Utils del SDK](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 dentro de 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 el raycasting es costoso para el rendimiento
			})
		)
		if (result) {
			// hacer algo
		}
	})
```

## Colisionar con el jugador

Puedes detectar avatares 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 (principal).

Ambas capas pueden combinarse o usarse independientemente. El valor predeterminado `collisionMask` de un raycast es `CL_PHYSICS`, que NO impacta avatares — debes habilitarlo explícitamente.

```ts
// impacta solo al jugador local (ignora otros avatares)
raycastSystem.registerLocalDirectionRaycast(
  {
    entity: myEntity,
    opts: {
      direction: Vector3.Forward(),
      collisionMask: ColliderLayer.CL_MAIN_PLAYER,
    },
  },
  (raycastResult) => {
    if (raycastResult.hits.length > 0) {
      console.log('impactó 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 avatares remotos (sin id de entidad local de la escena)
    console.log(raycastResult.hits)
  }
)
```

Cuando un raycast impacta al jugador local, el `hit.entityId` es `engine.PlayerEntity`. `0`) ya que el jugador remoto no es una entidad en el mundo de tu escena — pero el impacto sigue informándose con su `posición`, `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 la callback.
{% endhint %}

## Raycasts desde el jugador

Para trazar un rayo desde la posición del jugador en la dirección a la que mira la cámara, puedes trazar un rayo usando la cámara o el avatar [Entidades 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á te convenga usar [Pointer events](/creator/content-creator-es/escenas-sdk7/interactividad/eventos-de-boton/click-events.md) en lugar de raycasts.
{% endhint %}

El siguiente ejemplo traza un rayo desde la posición de la cámara del jugador hacia delante, usando la `engine.CameraEntity` entidad.

```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 3ª persona, el cursor podría en el futuro no comportarse igual que en 1ª 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 rayo 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 rayo desde la posición del cursor hacia el mundo 3D. Después comprobamos si el rayo impactó alguna entidad 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 del 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("entidad: ", entity)
        }
      }
    )
}

```

{% hint style="info" %}
**💡 Consejo**: En este ejemplo usamos el botón primario (E) para activar el raycast. No usamos el botón del puntero (clic izquierdo) porque hacer clic y arrastrar también desplaza el ángulo de la cámara de forma predeterminada. Si quieres evitar rotar la cámara mientras arrastras, puedes usar un [Virtual Camera](/creator/content-creator-es/escenas-sdk7/conceptos-basicos-de-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 que se intersectan. El rayo se traza comenzando en la posición de la entidad, tal como la define el componente Transform y afectado por el 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, afectada también 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, por ejemplo, para 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 exacta 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 dos 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 enum, para definir si el rayo devolverá todas las entidades 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 entidades impactadas, desde el origen hasta la distancia máxima del rayo.
* `collisionMask`: Detecta solo colisiones con ciertas capas de colisión. Usa esto junto con una capa de colisión personalizada, o para detectar solo la capa de física o la de pointer events. Ver [capas de colisión](/creator/content-creator-es/escenas-sdk7/conceptos-basicos-de-contenido-3d/colliders.md#collision-layers). De forma predeterminada, el valor es `ColliderLayer.CL_POINTER | ColliderLayer.CL_PHYSICS`.
* `originOffset`: En lugar de iniciar el raycast desde la posición de origen de la entity, agrega un offset para iniciar la consulta desde una posición relativa. Por ejemplo, puedes usar un offset pequeño para evitar que el rayo choque contra el propio modelo 3D de la entity.
* `continuous`: Si es true, seguirá ejecutando una consulta raycast en cada frame. Si es false, el rayo solo se usará en el frame actual. De forma predeterminada, este valor es false.

{% hint style="warning" %}
**📔 Nota**: La `continuous` propiedad debe usarse con cautela, 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 un intervalo regular más espaciado, ver [raycasting recurrente](#recurrent-raycasting).
{% endhint %}

El siguiente ejemplo usa una rotación global para determinar la dirección y solo devuelve la primera entity que recibe un impacto 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 ejemplo siguiente lanza un rayo en la dirección frontal de la entity, devolviendo solo el primer elemento impactado. Lo hace de forma continua. También incluye un pequeño offset de 0.5 para evitar que el rayo golpee el collider propio de la 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 ejemplo traza un rayo entre dos entities. Devuelve todas las entities que son impactadas en el trayecto.

```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 sencilla 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 una lógica personalizada más avanzada.
{% endhint %}

Después de crear un componente Raycast, la entity a la que se añade este componente tendrá un `RaycastResult` componente RaycastResult. 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 desde la que se originó el rayo, relativa a la escena.
* `direction`: La dirección global hacia la que apuntaba el rayo, como un `Vector3`.
* `hits`: Un arreglo con un objeto por cada entidad que fue impactada. Si no hubo entidades impactadas, este arreglo está vacío. Si el raycast usó `RaycastQueryType.RQT_HIT_FIRST`, este arreglo solo contendrá un objeto.

Cada objeto en el `hits` arreglo incluye:

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

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

```typescript

const rayEntity = engine.addEntity()

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

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

El siguiente ejemplo muestra cómo puedes acceder a `RaycastResult` components de todas las entities en la escena, usando una [consulta de components](/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 búsqueda de rutas, comprobación de línea de visión, seguimiento de proyectiles, etc.), quizá quieras usar diferentes [capas de colisión](/creator/content-creator-es/escenas-sdk7/conceptos-basicos-de-contenido-3d/colliders.md#collision-layers), para evitar calcular colisiones irrelevantes.


---

# 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.
