
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.

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

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ónAim- aquí es donde colocaremos el sistema Niagara de PunteríaProjectile- aquí es donde colocaremos el Proyectil cuando no está siendo sostenido por la otra manoSlingLeft- aquí es donde adjuntaremos el sistema Niagara de la Honda en el lado izquierdoSlingRight- aquí es donde adjuntaremos el sistema Niagara de la Honda en el lado derecho

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.

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 Typese establece enAttachment Grippara que la honda esté adjunta a la mano mientras se agarraGameplay Tagsse establecen enDropType.OnPrimaryGripReleaseyGrabType.OnPrimaryGrippara permitir agarre/suelta con controles por defecto- Habilitar
Simulate Physicspara 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 - Agregamos un componente
Hand Socket BasePrimaryGrippara 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 Handpara que un agarre con la mano izquierda use la pose reflejada - Habilitar
Use Custom Pose Deltaspara que la pose de la mano que hemos configurado se use realmente

Componente PrimaryGrip con pose de mano - Habilitar
- Agregamos un componente
SceneProjectileOriginy lo adjuntamos al socketProjectile
Componente de origen del proyectil - Agregamos un
GrippableStaticMeshComponentProjectiley lo adjuntamos alProjectileOrigin, y lo configuramos correctamente:Slot Default Grip TypeyFree Default Grip Typese establecen enCustom Gripya que tendremos comportamiento personalizado mientras el proyectil se sostieneGameplay Tagsse establecen enDropTypeyGrabTypepara deshabilitar agarre/suelta por defecto (solo lo habilitaremos cuando la Honda misma esté siendo sostenida)

Componente del proyectil - Agregamos un componente
Hand Socket BaseProjectileGrippara 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 Handpara que un agarre con la mano izquierda use la pose reflejada - Establecer
Mirror AxisenYpara que la pose de la mano sea correcta cuando se usa la mano izquierda para agarrar el proyectil - Habilitar
Use Custom Pose Deltaspara que la pose de la mano que hemos configurado se use realmente

Componente ProjectileGrip con pose de mano - Habilitar
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 TagsGrabType.OnPrimaryGrip/DropType.OnPrimaryGripReleaseal componente del proyectilOnGripRelease- deshabilitar el agarre/suelta del proyectil removiendo los Gameplay TagsGrabType.OnPrimaryGrip/DropType.OnPrimaryGripReleasedel componente del proyectil

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 eventoTickdel actorOnDropped- lanzar un proyectil y devolver el componente del proyectil a su ubicación/orientación originalEvent Tick- si el proyectil está siendo sostenido, actualizar su posición/orientación a la de la mano que lo sostiene

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 Rotationdesde el componente del proyectil hacia donde su posición original está actualmente - Generamos un nuevo
BP_Projectiley establecemos su orientación según la dirección del lanzamiento - Reproducimos un sonido 'whoosh' para indicar un lanzamiento exitoso

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

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.

Luego creamos un Sistema Niagara con 2 emisores, uno para cada lado de la 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 NiagaraSlingMiddle- el fin de ambas mitades de la honda, relativo al componente del sistema NiagaraSlingEnd- el inicio de la segunda mitad de la honda, relativo al componente del sistema NiagaraSlingColor- el color de las hondasSlingWidth- 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:
SlingStartpermanece en(0, 0, 0)que corresponde a la ubicación del socketSlingLeftSlingMiddlese establece en(9, 0, -1)que corresponde al medio del proyectilSlingEndse establece en(18, 0, 0)que corresponde a la ubicación del socketSlingRight- Podríamos agregar algo de lógica a
Begin Playpara tomar realmente el valor apropiado del socket y establecerlo, dejamos esto como ejercicio para el lector
- Podríamos agregar algo de lógica a
SlingWidthse establece en1.0que es lo suficientemente grueso para 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

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.

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.

Luego creamos un Sistema Niagara con 1 emisor.

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 NiagaraAimColor- el color del haz de punteríaAimWidth- 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:
AimEndse 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 correctaAimWidthse establece en1.0que es lo suficientemente grueso para la puntería

Ahora necesitamos asegurar que:
- 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
- la dirección del haz de puntería coincida con la dirección a la que el proyectil se lanzaría ahora mismo, y
- 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

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)


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.

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
PhysicsOriginque es el punto fijo de la restricción, que no simula física y no está afectado por la gravedad - Un componente
PhysicsProjectileque es el proxy invisible para el proyectil, que simula física y está afectado por la gravedad - Un componente
PhysicsConstraintque 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 Collisionse establece enNo CollisionHidden in Gameestá habilitado, ya que solo usamos esto como punto de referencia para el PhysicsConstraint

El PhysicsProjectile tiene las siguientes propiedades:
Simulate Physicsestá habilitadoCollisionse establece enPhysics Only, y todas las respuestas de colisión se establecen enIgnoreHidden in Gameestá habilitado, ya que solo usamos esto para la simulación mientras el proyectil no se sostiene

El PhysicsConstraint tiene las siguientes propiedades:
- Está colocado en el socket
Projectilede la honda - Los
Component Namesde la restricción se establecen enPhysicsOriginyPhysicsProjectile(esto tiene que coincidir exactamente con los nombres de los componentes) Disable Collisionestá habilitado, ya que solo dejamos que el PhysicsProjectile se mueva una cantidad muy limitada (2 cm) dentro de la hondaParent Dominatesestá 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 MotionenLimitedy establecemos elLimiten 2 cm - Establecemos los
Angular LimitsenLockedya que no nos interesan las rotaciones por ahora - Establecemos el
Position Targetdel Linear Motor en0, 0, 0con fuerza 25 - Establecemos el
Velocity Targetdel Linear Motor en0, 0, 0con fuerza 1


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.


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

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
GrippableSphereComponentpara el agarre del proyectil (en lugar de unGrippableStaticMeshComponent), 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
