Raycasting
Usa raycasting para trazar una línea en el espacio y consultar colisiones con entidades en la escena.
El raycast (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 proyectiles, algoritmos de búsqueda de rutas 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 hacia la que está mirando, ver eventos de botones para más detalles sobre esto. Este documento cubre cómo trazar un rayo invisible desde cualquier posición y dirección arbitrarias, independiente de las acciones del jugador, que puedes usar en muchos otros escenarios.
Ten en cuenta que los raycasts solo impactan objetos con colliders. Así que si deseas detectar impactos de rayos contra un modelo 3D, o bien:
El modelo debe contener mallas collider.
El
GLTFContainerdebe configurarse para usar la geometría visible con máscaras de colisión.Añadir un componente MeshCollider.
También es buena práctica asignar capas de colisión a modelos 3D, de modo que los rayos solo necesiten 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 distintas:
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 orientación.
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 objetivo global en la escena. Ignora la rotación de la entidad. Útil por ejemplo para crear juegos de defensa de torres; la torreta de cada torre puede apuntar a una coordenada concreta 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 ambas entidades.
El siguiente código crea un raycast con una dirección local:
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 callback
}
)Usa las siguientes funciones para crear raycasts proporcionando la dirección de diferentes maneras:
raycastSystem.registerLocalDirectionRaycast(): crea un raycast con una local dirección. Elcampodirectionespera unVector3que describa un vector relativo a la entidad y su rotación (por ejemplo,Vector3.Forward()terminaría usando el vector forward del transform de la entidad): crea un raycast con una global dirección. Elcampodirectionespera unraycastSystem.registerGlobalDirectionRaycast()que describe la dirección global.raycastSystem.registerGlobalTargetRaycast() objetivo global : crea un raycast con una dirección definida por unaposición. Eldirectionespera untargetque describe una posición global en la escena.raycastSystem.registerTargetEntityRaycast() entidad objetivo : crea un raycast con una dirección definida por una: crea un raycast con una dirección definida hacia unatargetEntity
el campo espera una referencia a una entidad; la posición de esa entidad se usará como objetivo del rayo.
Los siguientes campos opcionales están disponibles al crear un rayo con cualquiera de los métodos anteriores:: maxDistance númeropara establecer la longitud con la que se trazará este rayo. Si no se establece, el valor por defecto es 16 metros.: queryType RaycastQueryTypevalor enum, para definir si el rayo devolverá todas las entidades impactadas o solo la primera. Están disponibles las siguientes opciones:: RaycastQueryType.RQT_HIT_FIRST (por defecto)solo devuelve la primera entidad impactada, empezando 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 offset para iniciar la consulta desde una posición relativa. Por ejemplo, puedes usar un pequeño offset para evitar que el rayo colisione con el propio collider de la entidad. Si no se establece, el valor por defecto es.propiedad collisionMask,Vector3.Zero() capas de colisión: Detectar únicamente 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 capa de eventos pointer. VerColliderLayer.CL_PHYSICS.. Si no se establece, la capa por defecto usada escontinuous: 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 por defecto es false.
campoAl establecer la dirección con una dirección local o global, elque describa un vector relativo a la entidad y su rotación (por ejemplo,.campo predetermina a
Al establecer la dirección con un objetivo global, elAl establecer la dirección con una dirección local o global, el: En lugar de iniciar el raycast desde la posición de origen de la entidad, añade un offset para iniciar la consulta desde una posición relativa. Por ejemplo, puedes usar un pequeño offset para evitar que el rayo colisione con el propio collider de la entidad. Si no se establece, el valor por defecto es.globalTarget
: crea un raycast con una dirección definida hacia unaAl establecer la dirección con un objetivo entidad, el: En lugar de iniciar el raycast desde la posición de origen de la entidad, añade un offset para iniciar la consulta desde una posición relativa. Por ejemplo, puedes usar un pequeño offset para evitar que el rayo colisione con el propio collider de la entidad. Si no se establece, el valor por defecto es.
📔 Nota: El . Si no se establece, la capa por defecto usada es campo predetermina a la entidad raíz de la escena, ubicada en esta 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 sistema (o la función interval en la librería Utils) para ejecutar consultas de raycast en intervalos regulares más espaciados, ver.
raycasting recurrente
📔 Nota: targetEntity: targetEntity,, queryType y ColliderLayer deben importarse vía
raycastSystem
Ver Imports para ver cómo manejar estos fácilmente.
import { raycastSystem, RaycastQueryType, ColliderLayer } from "@dcl/sdk/ecs"
Resultado del raycast
La función callback que maneja el raycast recibe un objeto que contiene datos sobre el propio rayo y sobre las entidades que fueron impactadas.globalOrigincampo: La posición donde se originó el rayo, relativa a la escena.espera un.: La dirección global hacia la que apuntaba el rayo, como unhitsvalor enum, para definir si el rayo devolverá todas las entidades impactadas o solo la primera. Están disponibles las siguientes opciones:: 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ó
, este arreglo contendrá solo un objeto. : La dirección global hacia la que apuntaba el rayo, como un Cada objeto en el
arreglo incluye:entityId: Número Id de la entidad que fue impactada por el rayo.: meshName Stringposición: espera un 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.para la posición donde el rayo se 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 QuaternionLa función callback que maneja el raycast recibe un objeto que contiene datos sobre el propio rayo y sobre las entidades que fueron impactadas.: espera un para el ángulo de la normal del impacto en el espacio mundial.campo: La posición donde se originó el rayo, relativa a la escena.espera un.
para la posición donde el rayo se origina (relativa a la escena)
📔 Notaconsole.log('no se impactaron entidades')
: Puedes obtener un resultado de raycast al impactar una entidad en otra escena.
Manejar entidades impactadas arreglo incluye: Cuando obtienes un resultado de raycast que impactó una entidad, puedes usar el para interactuar con la entidad y sus componentes. Una entidad esnada más que un número arreglo incluye: , así que el valor en sí mismo puede interpretarse como un Entity
Collision layers
console.log(transform.position) propiedad collisionMask, Es buena práctica comprobar colisiones solo contra entidades relevantes, para hacer la escena más eficiente. El capas de colisióncampo permite listar únicamente capas de colisión específicas, que pueden incluir la capa de física (que bloquea el movimiento del jugador), la capa pointer (que se usa para eventos de puntero) y 8 capas personalizadas que puedes asignar libremente según tus necesidades. Ver
. Por defecto, todas las capas se detectan. propiedad collisionMask, Por defecto, el ColliderLayer.CL_POINTER y ColliderLayer.CL_PHYSICScampo está configurado para responder a ambas capas | . Puedes cambiar este valor para listar solo una de ellas, o para incluir capas personalizadas. Usa el
log(raycastResult.hits)
Raycasting recurrente targetEntity: targetEntity,Al usar las funciones del . Si no se establece, la capa por defecto usada es , el comportamiento por defecto es crear un solo rayo, que consultará colisiones una vez. Como alternativa, puedes establecer el true campo a
para ejecutar una consulta y la función callback en cada tick del bucle del juego.
📔 Nota: El . Si no se establece, la capa por defecto usada es continuous: true,
esta propiedad debe usarse con precaución, ya que ejecutar una consulta de raycast en cada frame puede ser muy costoso para el rendimiento. Cuando ya no sean necesarios, elimina los raycasts recurrentes. Para hacerlo, debes usar.
raycastSystem.removeRaycasterEntity(myEntity) esta 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 sistema (o la Cuando sea posible, usa un sistema (o la
MeshCollider.setBox(cubeEntity) El ejemplo anterior ejecuta un raycast recurrente cada 0.1 segundos. Usa un componente timer y la propiedad dt
para una forma más sencilla de ejecutar una función en un intervalo fijo.
Raycasts vía un sistema Otra forma de realizar raycasts recurrentes es ejecutarlos desde la función recurrente de un sistema. Esto te permite tener mucho más control sobre cuándo y cómo funcionan. En lugar de registrar una función 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 sistema.
if (result) // hacer algo
Colisionar con el jugador No puedes impactar directamente el avatar del jugador ni los de otros jugadores con un rayo, pero como solución alternativa puedes posicionar una entidad invisible que ocupe el mismo espacio que un jugador usando elcomponente AvatarAttach
, y comprobar colisiones con ese cubo.
Raycasts desde el jugador Para trazar un rayo desde la posición del jugador en la dirección a la que apunta la cámara, puedes trazar un rayo usando la cámara o el avatar.
en lugar de raycasts. El siguiente ejemplo traza un rayo desde la posición de la cámara del jugador hacia adelante, usando la entidad engine.CameraEntity
📔 Notaconsole.log(raycastResult)
: 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.
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.
Sintaxis avanzada
para fijar el ángulo de la cámara.
Crear un componente Raycast
Un componente Raycast describe el rayo invisible que se usa para consultar entidades intersectadas. El rayo se traza empezando en la posición de la entidad, según lo definido por el componente Transform y afectado por el de cualquier entidad padre. La dirección puede definirse de varias maneras,
campoLos rayos se definen usando los siguientes datos:$case: Un objeto que contiene un campo$case:para seleccionar el tipo de dirección, y un campo adicional que dependerá de este tipo, que determina dicha dirección. Los siguientes son los valores aceptados paraLOCAL_DIRECTION: 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 orientación. La rotación se define por el campolocalDirectionespera uncomo unque describe una rotación.GLOBAL_DIRECTION: 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 campolocalDirectionespera uncomo unglobalDirectionGLOBAL_TARGETAl establecer la dirección con un objetivo global, ellocalDirectionespera un: Traza una línea entre la posición de la entidad y una posición objetivo global en la escena. Ignora la rotación de la entidad. Útil para crear juegos de defensa de torres; la torreta de cada torre puede apuntar a una coordenada concreta en el espacio. El objetivo se define por elque describe la posición global.TARGET_ENTITY: crea un raycast con una dirección definida hacia una: 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 ambas entidades. El objetivo se define por el campo
Los siguientes campos opcionales están disponibles al crear un rayo con cualquiera de los métodos anteriores:: maxDistance sujetando una referencia a la entidad.para establecer la longitud con la que se trazará este rayo. Si no se establece, el valor por defecto es 16 metros.: queryType RaycastQueryTypesolo devuelve la primera entidad impactada, empezando desde el punto de origen.para establecer la longitud con la que se trazará este rayo.valor enum, para definir si el rayo devolverá todas las entidades impactadas o solo la primera. Están disponibles las siguientes opciones:RaycastQueryType.RQT_QUERY_ALL
propiedad collisionMask,Vector3.Zero() capas de colisióncampo permite listar únicamente capas de colisión específicas, que pueden incluir la capa de física (que bloquea el movimiento del jugador), la capa pointer (que se usa para eventos de puntero) y 8 capas personalizadas que puedes asignar libremente según tus necesidades. Ver: devuelve todas las entidades impactadas, desde el origen hasta la distancia máxima del rayo.: solo devuelve la primera entidad impactada, empezando desde el punto de origen.. Si no se establece, la capa por defecto usada es: En lugar de iniciar el raycast desde la posición de origen de la entidad, añade un offset para iniciar la consulta desde una posición relativa. Por ejemplo, puedes usar un pequeño offset para evitar que el rayo colisione con el propio modelo 3D de la entidad.
📔 Nota: El . Si no se establece, la capa por defecto usada es campo predetermina a la entidad raíz de la escena, ubicada en esta 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 sistema (o la función interval en la librería Utils) para ejecutar consultas de raycast en intervalos regulares más espaciados, ver.
: Si es true, seguirá ejecutando una consulta de raycast en cada frame. Si es false, el rayo solo se usará en el frame actual. Por defecto este valor es false.
queryType: RaycastQueryType.RQT_HIT_FIRST
continuous: true
queryType: RaycastQueryType.RQT_QUERY_ALL
📔 NotaComponente de resultados de Raycast : La forma más sencilla de tratar los resultados de raycast es usarraycastEventSystem, y registrar una función callback como parte de la misma declaración que crea el rayo. El componente RaycastResult
se usa internamente por esa interfaz, pero también se expone para permitir lógica personalizada más avanzada. , y registrar una función callback como parte de la misma declaración que crea el rayo. El componente Después de crear un componente Raycast, la entidad a la que se añade este componente tendrá un componente
El , y registrar una función callback como parte de la misma declaración que crea el rayo. El componente RaycastResult. Este componente incluye información sobre cualquier impacto del rayo. Configura un sistema para comprobar estos datos.
La función callback que maneja el raycast recibe un objeto que contiene datos sobre el propio rayo y sobre las entidades que fueron impactadas.globalOrigincampo: La posición donde se originó el rayo, relativa a la escena.espera un.: La dirección global hacia la que apuntaba el rayo, como unhitsvalor enum, para definir si el rayo devolverá todas las entidades impactadas o solo la primera. Están disponibles las siguientes opciones:: 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ó
, este arreglo contendrá solo un objeto. : La dirección global hacia la que apuntaba el rayo, como un Cada objeto en el
arreglo incluye:entityId: Número Id de la entidad que fue impactada por el rayo.: meshName Stringposición: espera un 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.para la posición donde el rayo se 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 QuaternionLa función callback que maneja el raycast recibe un objeto que contiene datos sobre el propio rayo y sobre las entidades que fueron impactadas.: espera un para el ángulo de la normal del impacto en el espacio mundial.campo: La posición donde se originó el rayo, relativa a la escena.espera un.
el componente contiene los siguientes datos:
console.log(rayResult.hits) , y registrar una función callback como parte de la misma declaración que crea el rayo. El componente El siguiente ejemplo muestra cómo puedes acceder a los componentes de todas las entidades en la escena, usando una.
📔 Notaconsole.log(result.hits)
: Los resultados de un raycast no llegan en el mismo tick del bucle de juego en el que creaste el raycast. Los resultados pueden tardar uno o varios ticks en llegar. capas de colisiónEn una escena donde usas múltiples tipos de rayos para diferentes propósitos (como para búsqueda de rutas, comprobación de línea de visión, trazado de proyectiles, etc.), puede que quieras usar diferentes máscaras de colisión, para evitar calcular colisiones irrelevantes.
Última actualización