Devlog: Construyendo una Honda para Unreal Engine

Devlog: Construyendo una Honda para Unreal Engine

Thijs ReusThijs Reus
·12 de diciembre de 2025·27 min. de lectura
Tenga en cuenta que esta publicación ha sido traducida automáticamente.

En esta publicación, miramos construir una honda en Unreal Engine, como alternativa a las mecánicas típicas de pistola para disparar un proyectil. Una honda es una herramienta de 2 manos, una mano para sostener y apuntar, y la otra mano para agarrar y tirar hacia atrás el proyectil para determinar la puntería final y velocidad de lanzamiento, y soltar el proyectil para lanzarlo.

Honda en Realidad Mixta
Honda en Realidad Mixta

Stack Tecnológico

Para esta exploración, estamos usando el siguiente stack tecnológico:

Desglose de la Honda

Desglosamos la implementación de la honda en las siguientes partes:

  • Malla de la honda - una malla en forma de Y que puede ser agarrada
  • Malla del proyectil - una malla esférica que puede ser agarrada cuando la Honda está siendo sostenida por la otra mano
  • Actor Blueprint - combina los diversos componentes y agrega lógica por ejemplo para lanzar un proyectil
  • Manejo de agarre/suelta del proyectil - la lógica para mover el proyectil cuando se agarra, y lanzar un proyectil cuando se suelta
  • Sistema Niagara de la honda - muestra la honda dinámica entre la malla de la Honda y el proyectil antes de que el proyectil sea lanzado
  • Sistema Niagara de puntería - muestra un rayo láser en la dirección donde el proyectil será lanzado para ayudar a apuntar
  • Restricción de Física - simula el proyectil colgando en la honda para darle un poco más de dinámica mientras se mueve

Malla de la Honda

Cualquier malla en forma de Y puede usarse para representar la honda. Si no hay tal malla disponible, podemos crearla fácilmente con el Modo de Modelado de Unreal Engine usando los siguientes pasos:

  • Crear un cilindro delgado para la parte I
  • Crear un cilindro más grande y restar un círculo más pequeño de su centro para crear una forma O
  • Cortar con plano la forma O para crear una forma U
  • Colocar la forma U encima de la forma I, y fusionarlas para crear la forma Y final
  • Mover el pivote a center-min-Z para que esté en la parte inferior
Malla en forma de Y para la honda
Malla en forma de Y para la honda

En el Editor de Malla Estática, podemos agregar algunos Sockets para marcar la posición y orientación de puntos significativos que usaremos más adelante en el Blueprint:

  • Grip - aquí es donde la mano se ajustará al agarrar la honda, para que siempre se sostenga en la misma posición/orientación
  • Aim - aquí es donde colocaremos el sistema Niagara de Puntería
  • Projectile - aquí es donde colocaremos el Proyectil cuando no está siendo sostenido por la otra mano
  • SlingLeft - aquí es donde adjuntaremos el sistema Niagara de la Honda en el lado izquierdo
  • SlingRight - aquí es donde adjuntaremos el sistema Niagara de la Honda en el lado derecho
Sockets para la honda
Sockets para la honda

Usar sockets hace más fácil usar después diferentes mallas de honda con el mismo Blueprint.

Malla del Proyectil

Para la malla del Proyectil usamos una Esfera simple con el pivote en el centro.

Esfera para el Proyectil
Esfera para el Proyectil

Actor Blueprint

Creamos un nuevo Blueprint con GrippableStaticMeshActor del VR Expansion Plugin como la clase padre, que ya implementa la VRGrip Interface y proporciona una base excelente para nuestra honda:

  • Configuramos las propiedades del actor
    • Usar la malla de la honda como Static Mesh en el componente raíz
    • Slot Default Grip Type se establece en Attachment Grip para que la honda esté adjunta a la mano mientras se agarra
    • Gameplay Tags se establecen en DropType.OnPrimaryGripRelease y GrabType.OnPrimaryGrip para permitir agarre/suelta con controles por defecto
    • Habilitar Simulate Physics para que la honda no flote en el aire mientras no se sostiene
    • Los presets de colisión se establecen en PhysicsActor
    Blueprint usando la malla de la honda
    Blueprint usando la malla de la honda
  • Agregamos un componente Hand Socket Base PrimaryGrip para la ubicación/orientación del agarre primario, y ajustamos la pose de la mano para que envuelva correctamente la honda
    • Habilitar Flip For Off Hand para que un agarre con la mano izquierda use la pose reflejada
    • Habilitar Use Custom Pose Deltas para que la pose de la mano que hemos configurado se use realmente
    Componente PrimaryGrip con pose de mano
    Componente PrimaryGrip con pose de mano
  • Agregamos un componente Scene ProjectileOrigin y lo adjuntamos al socket Projectile
    Componente de origen del proyectil
    Componente de origen del proyectil
  • Agregamos un GrippableStaticMeshComponent Projectile y lo adjuntamos al ProjectileOrigin, y lo configuramos correctamente:
    • Slot Default Grip Type y Free Default Grip Type se establecen en Custom Grip ya que tendremos comportamiento personalizado mientras el proyectil se sostiene
    • Gameplay Tags se establecen en DropType y GrabType para deshabilitar agarre/suelta por defecto (solo lo habilitaremos cuando la Honda misma esté siendo sostenida)
    Componente del proyectil
    Componente del proyectil
  • Agregamos un componente Hand Socket Base ProjectileGrip para la ubicación/orientación del agarre del proyectil, y ajustamos la pose de la mano para que envuelva correctamente el proyectil
    • Habilitar Flip For Off Hand para que un agarre con la mano izquierda use la pose reflejada
    • Establecer Mirror Axis en Y para que la pose de la mano sea correcta cuando se usa la mano izquierda para agarrar el proyectil
    • Habilitar Use Custom Pose Deltas para que la pose de la mano que hemos configurado se use realmente
    Componente ProjectileGrip con pose de mano
    Componente ProjectileGrip con pose de mano

Nota: Normalmente adjuntaríamos el componente PrimaryGrip al socket Grip de la malla de la honda, sin embargo este componente no funciona bien con sockets. Así que en su lugar, en el evento Begin Play, establecemos su ubicación/orientación a la del socket.

Manejo de Agarre/Suelta del Proyectil

Actualmente podemos agarrar la honda con cualquiera de las manos, pero aún no podemos interactuar con el proyectil, ya que hemos establecido los valores por defecto para ignorar cualquier acción de agarre/suelta.

Así que agregamos algo de lógica cuando la honda se agarra/se suelta para habilitar/deshabilitar el agarre del proyectil, implementando los métodos correspondientes de la VR Grip Interface en el actor:

  • OnGrip - habilitar el agarre/suelta del proyectil agregando los Gameplay Tags GrabType.OnPrimaryGrip / DropType.OnPrimaryGripRelease al componente del proyectil
  • OnGripRelease - deshabilitar el agarre/suelta del proyectil removiendo los Gameplay Tags GrabType.OnPrimaryGrip / DropType.OnPrimaryGripRelease del componente del proyectil
Lógica OnGrip / OnGripRelease
Lógica OnGrip / OnGripRelease

Ahora necesitamos manejar cuando el proyectil mismo se agarra implementando los eventos correspondientes en el componente Projectile:

  • OnGripped - almacenar la información del agarre, y comenzar a actualizar la ubicación/orientación del componente del proyectil basándose en la ubicación/orientación de la mano en el evento Tick del actor
  • OnDropped - lanzar un proyectil y devolver el componente del proyectil a su ubicación/orientación original
  • Event Tick - si el proyectil está siendo sostenido, actualizar su posición/orientación a la de la mano que lo sostiene
Lógica OnGripped / OnDropped / Tick del Proyectil
Lógica OnGripped / OnDropped / Tick del Proyectil

Para lanzar un proyectil cuando el componente del proyectil se suelta, implementamos nuestro método LaunchProjectile:

  • Nos aseguramos de que el componente del proyectil esté en un rango válido (por ejemplo, al menos 20 cm detrás de su posición original), de lo contrario no lanzamos un proyectil, para que el proyectil pueda volver sin ser lanzado
  • Determinamos la dirección del lanzamiento encontrando la Look At Rotation desde el componente del proyectil hacia donde su posición original está actualmente
  • Generamos un nuevo BP_Projectile y establecemos su orientación según la dirección del lanzamiento
  • Reproducimos un sonido 'whoosh' para indicar un lanzamiento exitoso
Lógica de lanzamiento del proyectil
Lógica de lanzamiento del proyectil

Resultado Intermedio 1

El video a continuación muestra que ahora tenemos una honda funcional en nuestro mapa de prueba de Realidad Mixta.

Video Vista previa

Al hacer clic en el botón de reproducción, se incrustará el reproductor de YouTube y se pueden establecer cookies de terceros y recopilar datos de YouTube.

Por supuesto, podemos agregar muchas mejoras, algunas de las cuales cubriremos en las siguientes secciones.

Sistema Niagara de la Honda

Actualmente el proyectil parece estar flotando en la honda, así que hagamos una honda entre la honda y el proyectil.

Primero creamos un material para la honda como se muestra en la imagen a continuación. Como usaremos haces Niagara para la honda, y el material de haz por defecto es aditivo y tiene un gradiente (lo que significa que no es completamente opaco), creamos nuestro propio material de haz que puede ser completamente opaco, e incluso agrega un poco de desvanecimiento a lo largo del borde del haz para dar la idea de un haz no plano.

Material de la honda para los haces Niagara
Material de la honda para los haces Niagara

Luego creamos un Sistema Niagara con 2 emisores, uno para cada lado de la honda.

Sistema Niagara de la Honda con un emisor para cada mitad de la honda
Sistema Niagara de la Honda con un emisor para cada mitad de la honda
Segundo emisor de mitad de honda
Segundo emisor de mitad de honda

Los emisores se establecen en Local Space para que la honda se mueva con la honda, de lo contrario las hondas pueden quedarse atrás cuando se mueve la honda. Como bonus, no necesitamos actualizar el punto de inicio y fin cada frame, ya que permanecen constantes relativos a la honda.

Definimos 5 parámetros para controlar la honda desde el blueprint:

  • SlingStart - el inicio de la primera mitad de la honda, relativo al componente del sistema Niagara
  • SlingMiddle - el fin de ambas mitades de la honda, relativo al componente del sistema Niagara
  • SlingEnd - el inicio de la segunda mitad de la honda, relativo al componente del sistema Niagara
  • SlingColor - el color de las hondas
  • SlingWidth - el ancho de las hondas

Nota: la ubicación Beam End es relativa al Beam Start, así que en el emisor tenemos que restar el valor Beam Start del valor SlingMiddle para asegurar una posición correcta para el Beam End.

Ahora que el Sistema Niagara está listo, lo agregamos al blueprint de la honda, lo adjuntamos al socket SlingLeft, y proporcionamos algunos valores por defecto significativos para los parámetros:

  • SlingStart permanece en (0, 0, 0) que corresponde a la ubicación del socket SlingLeft
  • SlingMiddle se establece en (9, 0, -1) que corresponde al medio del proyectil
  • SlingEnd se establece en (18, 0, 0) que corresponde a la ubicación del socket SlingRight
    • Podríamos agregar algo de lógica a Begin Play para tomar realmente el valor apropiado del socket y establecerlo, dejamos esto como ejercicio para el lector
  • SlingWidth se establece en 1.0 que es lo suficientemente grueso para la honda
Blueprint de la honda con sistema Niagara de la honda
Blueprint de la honda con sistema Niagara de la honda

Ahora necesitamos asegurar que el medio de la honda siempre corresponda con la ubicación del proyectil, así que agregamos una nueva función UpdateSlingPosition al blueprint, y la llamamos en 2 ubicaciones en el EventGraph:

  • Después de que el proyectil ha sido movido de vuelta a su ubicación inicial después de ser soltado
  • Después de que el proyectil ha sido movido a la ubicación del controlador que agarra cuando se sostiene
Activando la función UpdateSlingPosition en el event graph
Activando la función UpdateSlingPosition en el event graph

Al actualizar el medio de la honda debemos asegurar que la posición que establecemos es relativa al componente del Sistema Niagara, ya que esto es lo que nuestro Sistema Niagara espera.

Implementación de la función UpdateSlingPosition
Implementación de la función UpdateSlingPosition

Ahora tenemos una honda funcional que se mueve con el proyectil, lo que ya mejora mucho la honda. En iteraciones futuras podríamos hacerla aún mejor, por ejemplo:

  • Ajustar el color y ancho de la honda cuando se alarga (agarrando el proyectil y moviéndolo hacia atrás) para indicar tensión creciente en la honda
  • Agregar una malla de 'cubo' que sostiene el proyectil, y adjuntar la honda a él (en lugar de conectar la honda al centro del proyectil)

Sistema Niagara de Puntería

Para ayudar al usuario a apuntar la honda, agregamos otro sistema Niagara para un láser que apunta en la dirección donde el proyectil será disparado. También indica cuándo el proyectil será lanzado cuando se suelte, ya que solo habilitamos el láser cuando el proyectil está a más de 15 cm de su origen original.

Primero creamos un material para la puntería como se muestra en la imagen a continuación, para que tengamos un poco más de transparencia hacia los bordes del haz. En lugar de Additive usamos un material Translucent, para que también sea visible en áreas donde passthrough está habilitado.

Material de puntería para los haces Niagara
Material de puntería para los haces Niagara

Luego creamos un Sistema Niagara con 1 emisor.

Sistema Niagara de Puntería con un solo emisor para el haz de puntería
Sistema Niagara de Puntería con un solo emisor para el haz de puntería

El emisor se establece en Local Space para que la puntería se mueva con la honda, de lo contrario la puntería puede quedarse atrás cuando se mueve la honda. Aquí asumimos que el inicio del haz de puntería siempre está en la ubicación del componente del sistema Niagara.

Definimos 3 parámetros para controlar la puntería desde el Blueprint:

  • AimEnd - el fin del haz de puntería, relativo al componente del sistema Niagara
  • AimColor - el color del haz de puntería
  • AimWidth - el ancho del haz de puntería

Ahora que el Sistema Niagara está listo, lo agregamos al blueprint de la honda, lo adjuntamos al socket Aim, y proporcionamos algunos valores por defecto significativos para los parámetros:

  • AimEnd se establece en (100, 0, 0) para que podamos verlo en el viewport del blueprint y verificar que está en la ubicación correcta y tiene la orientación correcta
  • AimWidth se establece en 1.0 que es lo suficientemente grueso para la puntería
Blueprint de la honda con sistema Niagara de Puntería
Blueprint de la honda con sistema Niagara de Puntería

Ahora necesitamos asegurar que:

  1. el haz de puntería solo sea visible cuando el proyectil está al menos a 15 cm de su origen original (donde soltarlo lanzaría un proyectil), y
  2. la dirección del haz de puntería coincida con la dirección a la que el proyectil se lanzaría ahora mismo, y
  3. el haz de puntería se detenga en el primer objeto/superficie visible que golpee (no debería pasar a través de objetos/superficies sólidas)

Para esto, agregamos una nueva función UpdateAimPosition al Blueprint, y la llamamos en 3 ubicaciones en el EventGraph:

  • Evento BeginPlay - esto asegura que el haz de puntería esté oculto al inicio del nivel, asumiendo que el proyectil está en su origen
  • Después de que el proyectil ha sido movido de vuelta a su ubicación inicial después de ser soltado
  • Después de que el proyectil ha sido movido a la ubicación del controlador que agarra cuando se sostiene
Activando la función UpdateAimPosition en el event graph
Activando la función UpdateAimPosition en el event graph

La implementación básicamente hace los siguientes pasos:

  • Mostrar u ocultar la puntería basándose en la distancia actual entre el proyectil y su origen original
  • Establecer la dirección del haz de puntería a la dirección del proyectil si se lanzaría ahora mismo
  • Hacer un LineTrace de visibilidad desde la ubicación de inicio de la puntería en la dirección de la puntería, y ajustar la longitud del haz de puntería en consecuencia (para que no pase a través de objetos/superficies sólidas)
Implementación de la función UpdateSlingPosition (1ra parte)
Implementación de la función UpdateSlingPosition (1ra parte)
Implementación de la función UpdateSlingPosition (2da parte)
Implementación de la función UpdateSlingPosition (2da parte)

Ahora apuntar es mucho más fácil, incluso cuando la posición de inicio de la puntería está ligeramente por debajo de la ubicación real de lanzamiento del proyectil. Esto no es un gran problema, dado la velocidad de lanzamiento relativamente alta, y el hecho de que actualmente el proyectil está afectado por la gravedad, mientras que la puntería es una línea recta.

Resultado Intermedio 2

El video a continuación muestra que ahora tenemos una honda en nuestro mapa de prueba de Realidad Mixta con una honda y puntería funcionales, que también indica al usuario cuándo un proyectil sería lanzado al soltar el proyectil, o cuándo simplemente volvería a su origen original.

Video Vista previa

Al hacer clic en el botón de reproducción, se incrustará el reproductor de YouTube y se pueden establecer cookies de terceros y recopilar datos de YouTube.

Por supuesto, aún podemos agregar algunas mejoras, específicamente una forma de hacer que la ubicación del proyectil sea menos rígida cuando no se sostiene, para que parezca que el proyectil está colgando en la honda.

Restricción de Física

Actualmente el proyectil está colgando muy rígidamente en la honda, lo cual no es muy agradable. Para hacer que el proyectil se mueva un poco basándose en el movimiento de la honda, podemos agregar un PhysicsConstraint a la honda. Hemos decidido simular un proxy invisible para el proyectil (PhysicsProjectile), y actualizar la ubicación del proyectil visible a la ubicación del proxy siempre que no se sostenga. De esa manera no necesitamos romper / reiniciar el PhysicsConstraint cada vez que el usuario agarra o suelta el proyectil.

Para esta configuración, necesitamos 3 componentes adicionales:

  • Un componente PhysicsOrigin que es el punto fijo de la restricción, que no simula física y no está afectado por la gravedad
  • Un componente PhysicsProjectile que es el proxy invisible para el proyectil, que simula física y está afectado por la gravedad
  • Un componente PhysicsConstraint que vincula ambos componentes y mantiene el PhysicsProjectile en el lugar correcto, incluso si movemos o rotamos la honda

El PhysicsOrigin tiene las siguientes propiedades:

  • Está colocado ligeramente por encima del ProjectileOrigin, en este caso 1 cm
  • Collision se establece en No Collision
  • Hidden in Game está habilitado, ya que solo usamos esto como punto de referencia para el PhysicsConstraint
Componente PhysicsOrigin en el blueprint de la honda
Componente PhysicsOrigin en el blueprint de la honda

El PhysicsProjectile tiene las siguientes propiedades:

  • Simulate Physics está habilitado
  • Collision se establece en Physics Only, y todas las respuestas de colisión se establecen en Ignore
  • Hidden in Game está habilitado, ya que solo usamos esto para la simulación mientras el proyectil no se sostiene
Componente PhysicsProjectile en el blueprint de la honda
Componente PhysicsProjectile en el blueprint de la honda

El PhysicsConstraint tiene las siguientes propiedades:

  • Está colocado en el socket Projectile de la honda
  • Los Component Names de la restricción se establecen en PhysicsOrigin y PhysicsProjectile (esto tiene que coincidir exactamente con los nombres de los componentes)
  • Disable Collision está habilitado, ya que solo dejamos que el PhysicsProjectile se mueva una cantidad muy limitada (2 cm) dentro de la honda
  • Parent Dominates está habilitado, ya que solo queremos mover el PhysicsProjectile, y consideramos el PhysicsOrigin un punto de referencia fijo dentro de la honda
  • Establecemos X / Y / Z Motion en Limited y establecemos el Limit en 2 cm
  • Establecemos los Angular Limits en Locked ya que no nos interesan las rotaciones por ahora
  • Establecemos el Position Target del Linear Motor en 0, 0, 0 con fuerza 25
  • Establecemos el Velocity Target del Linear Motor en 0, 0, 0 con fuerza 1
Componente PhysicsConstraint (1ra parte) en el blueprint de la honda
Componente PhysicsConstraint (1ra parte) en el blueprint de la honda
Componente PhysicsConstraint (2da parte) en el blueprint de la honda
Componente PhysicsConstraint (2da parte) en el blueprint de la honda

Para hacer que esto funcione correctamente al mover la honda, necesitamos despertar el PhysicsProjectile y ajustar el Reference Frame cada tick. Hacemos esto agregando una nueva función UpdatePhysicsConstraint, y llamándola al inicio del Event Tick en el EventGraph.

Event graph para actualizar la restricción de física cada tick
Event graph para actualizar la restricción de física cada tick
Implementación de UpdatePhysicsConstraint
Implementación de UpdatePhysicsConstraint

El resultado se puede ver en el video a continuación, que se ve mucho mejor con el proyectil colgando ahora.

Video Vista previa

Al hacer clic en el botón de reproducción, se incrustará el reproductor de YouTube y se pueden establecer cookies de terceros y recopilar datos de YouTube.

Mejoras Adicionales

La honda que hemos construido hasta ahora ya funciona bastante bien, pero por supuesto hay mejoras adicionales que se pueden hacer:

  • Habilitar el procesamiento de tick solo cuando la honda está siendo sostenida
  • Usar un GrippableSphereComponent para el agarre del proyectil (en lugar de un GrippableStaticMeshComponent), para que podamos hacerlo un poco más grande que el proyectil mismo para hacer el agarre del proyectil más fácil para el usuario (actualmente el usuario puede agarrar accidentalmente la honda misma cuando la mano está demasiado a la izquierda o derecha del proyectil)
  • Separar el proyectil de la honda (para que el usuario deba recoger un proyectil de otro lugar, y luego pueda usarlo con la honda)
  • Limitar el rango en el que un proyectil será lanzado, actualmente se permite cualquier dirección, incluso cuando no tiene sentido (por ejemplo, tirar el proyectil directamente hacia abajo a través de la honda)
  • Ajustar la velocidad del proyectil lanzado basándose en qué tan lejos se tiró el proyectil desde la honda

Conclusión

Una honda es una variación agradable de las mecánicas tradicionales de pistola y puede proporcionar inmersión adicional al proporcionar una forma divertida de apuntar y lanzar proyectiles en un entorno VR o MR.

Nosotros en Immerstory estamos emocionados de apoyar a nuestros clientes con sus experiencias inmersivas, y esperamos compartir más progreso de exploración pronto.

¿Qué experiencia inmersiva te gustaría ver? ¡Déjanos saber!

Recursos Adicionales

La documentación para el plugin MetaXR, específicamente el Mixed Reality Utility Kit que se usó para esta demo, se puede encontrar aquí

Los efectos de sonido en la aplicación demo han sido amablemente obtenidos de Sonniss GameAudioGDC

Más del blog