Cómo construir un juego de realidad virtual multijugador en tiempo real (Parte 1)

Publicado: 2022-03-10
Resumen rápido ↬ La realidad virtual es un nuevo medio inmersivo para explorar contenido, ya sea que ese contenido sea una película ( Life of Pi ), ​​un juego ( Beat Saber ) o una experiencia social (como se muestra en Ready Player One ). A pesar de su novedad, la realidad virtual no requiere un conjunto de herramientas drásticamente diferente para el diseño: las mismas herramientas que usamos para el desarrollo de juegos web, el modelado 3D y otras siguen siendo aplicables. Este tutorial aprovecha su familiaridad con el desarrollo web para comenzar con el desarrollo de realidad virtual.

En esta serie de tutoriales, crearemos un juego de realidad virtual multijugador basado en la web en el que los jugadores deberán colaborar para resolver un rompecabezas. Usaremos A-Frame para el modelado de realidad virtual, MirrorVR para la sincronización en tiempo real entre dispositivos y A-Frame Low Poly para la estética low-poly. Al final de este tutorial, tendrá una demostración en línea completamente funcional que cualquiera puede jugar.

Cada pareja de jugadores recibe un anillo de orbes. El objetivo es "encender" todos los orbes, donde un orbe está "encendido" si está elevado y brillante. Un orbe está "apagado" si está más bajo y tenue. Sin embargo, ciertos orbes "dominantes" afectan a sus vecinos: si cambia de estado, sus vecinos también cambian de estado. Solo el jugador 2 puede controlar los orbes dominantes, mientras que solo el jugador 1 puede controlar los orbes no dominantes. Esto obliga a ambos jugadores a colaborar para resolver el rompecabezas. En esta primera parte del tutorial, construiremos el entorno y agregaremos los elementos de diseño para nuestro juego de realidad virtual.

Los siete pasos de este tutorial se agrupan en tres secciones:

  1. Configuración de la escena (Pasos 1 y 2)
  2. Creación de los orbes (pasos 3 a 5)
  3. Cómo hacer que los orbes sean interactivos (pasos 6 y 7)
¡Más después del salto! Continúe leyendo a continuación ↓

Esta primera parte concluirá con un orbe en el que se puede hacer clic que se enciende y se apaga (como se muestra a continuación). Utilizará A-Frame VR y varias extensiones de A-Frame.

(Vista previa grande)

Preparando la escena

1. Vamos con una escena básica

Para comenzar, echemos un vistazo a cómo podemos configurar una escena simple con un suelo:

Crear una escena sencilla
Crear una escena simple (Vista previa grande)

Las primeras tres instrucciones a continuación están extraídas de mi artículo anterior. Comenzará configurando un sitio web con una sola página HTML estática. Esto le permite codificar desde su escritorio e implementarlo automáticamente en la web. El sitio web implementado se puede cargar en su teléfono móvil y colocar dentro de un auricular VR. Alternativamente, el sitio web implementado se puede cargar con un auricular VR independiente.

Comience navegando a glitch.com. Luego, haz lo siguiente:

  1. Haga clic en "Nuevo proyecto" en la parte superior derecha,
  2. Haga clic en "hola-página web" en el menú desplegable,
  3. A continuación, haga clic en index.html en la barra lateral izquierda. Nos referiremos a esto como su "editor".

Ahora debería ver la siguiente pantalla Glitch con un archivo HTML predeterminado.

Proyecto Glitch: el archivo index.html
Proyecto Glitch: el archivo index.html (vista previa grande)

Al igual que con el tutorial vinculado anterior, comience eliminando todo el código existente en el archivo index.html actual. Luego, escriba lo siguiente para un proyecto webVR básico, usando A-Frame VR. Esto crea una escena vacía utilizando la iluminación y la cámara predeterminadas de A-Frame.

 <!DOCTYPE html> <html> <head> <title>Lightful</title> <script src="https://aframe.io/releases/0.8.0/aframe.min.js"></script> </head> <body> <a-scene> </a-scene> </body> </html>

Levante la cámara a la altura de pie. Según las recomendaciones de A-Frame VR (problema de Github), envuelva la cámara con una nueva entidad y mueva la entidad principal en lugar de la cámara directamente. Entre sus etiquetas a-scene a en las líneas 8 y 9, agregue lo siguiente.

 <!-- Camera! --> <a-entity position="0 3 0"> <a-camera wasd-controls look-controls></a-camera> </a-entity>

Luego, agregue un cuadro grande para indicar el suelo, usando a-box . Coloque esto directamente debajo de su cámara de la instrucción anterior.

 <!-- Action! --> <a-box shadow width="75" height="0.1" depth="75" position="0 -1 0" color="#222"></a-box>

Su archivo index.html ahora debería coincidir exactamente con lo siguiente. Puede encontrar el código fuente completo aquí, en Github.

 <html> <head> <title>Lightful</title> <script src="https://aframe.io/releases/0.8.0/aframe.min.js"></script> </head> <body> <a-scene> <!-- Camera! --> <a-entity position="0 3 0"> <a-camera wasd-controls look-controls></a-camera> </a-entity> <!-- Action! --> <a-box shadow width="75" height="0.1" depth="75" position="0 -1 0" color="#222"></a-box> </a-scene> </body> </html>

Esto concluye la instalación. A continuación, personalizaremos la iluminación para una atmósfera más misteriosa.

2. Añadir ambiente

En este paso, configuraremos la niebla y la iluminación personalizada.

Una vista previa de una escena simple con un estado de ánimo oscuro.
Una vista previa de una escena simple con un ambiente oscuro (Vista previa grande)

Agregue una niebla, que oscurecerá los objetos lejanos para nosotros. Modifique la etiqueta a-scene a en la línea 8. Aquí, agregaremos una niebla oscura que oscurecerá rápidamente los bordes del suelo, dando el efecto de un horizonte distante.

 <a-scene fog="type: linear; color: #111; near:10; far:15"></a-scene>

El #111 gris oscuro se desvanece linealmente desde una distancia de 10 a una distancia de 15. Todos los objetos a más de 15 unidades de distancia están completamente oscurecidos, y todos los objetos a menos de 10 unidades de distancia son completamente visibles. Cualquier objeto en el medio está parcialmente oscurecido.

Agregue una luz ambiental para iluminar los objetos del juego y una luz unidireccional para acentuar las superficies reflectantes que agregará más adelante. Colóquelo directamente después de la etiqueta a-scene que modificó en las instrucciones anteriores.

 <!-- Lights! --> <a-light type="directional" castshadow="true" intensity="0.5" color="#FFF" position="2 5 0"></a-light> <a-light intensity="0.1" type="ambient" position="1 1 1" color="#FFF"></a-light>

Directamente debajo de las luces de la instrucción anterior, agregue un cielo oscuro. Observe que el #111 gris oscuro coincide con el de la niebla distante.

 <a-sky color="#111"></a-sky>

Esto concluye las modificaciones básicas del estado de ánimo y, en términos más generales, la configuración de la escena. Verifique que su código coincida exactamente con el código fuente del Paso 2 en Github. A continuación, agregaremos un orbe de baja poli y comenzaremos a personalizar la estética del orbe.

Creando los orbes

3. Crea un orbe Low-Poly

En este paso, crearemos un orbe giratorio y reflectante como se muestra a continuación. El orbe está compuesto por dos esferas estilizadas de bajo contenido de poliéster con algunos trucos para sugerir material reflectante.

Orbe giratorio y reflectante
(Vista previa grande)

Comience importando la biblioteca low-poly en su etiqueta head . Inserte lo siguiente entre las líneas 4 y 5.

 <script src="https://cdn.jsdelivr.net/gh/alvinwan/[email protected]/dist/aframe-low-poly.min.js"></script>

Cree un contenedor de carrusel, envoltura y orbe. El carousel contendrá múltiples orbes, el wrapper nos permitirá rotar todos los orbes alrededor de un eje central sin rotar cada orbe individualmente, y el container , como sugiere el nombre, contendrá todos los componentes del orbe.

 <a-entity> <a-entity rotation="0 90 0" class="wrapper" position="0 0 0"> <a-entity class="container" position="8 3 0" scale="1 1 1"> <!-- place orb here --> </a-entity> </a-entity> </a-entity>

Dentro del contenedor del orbe, agregue el orbe mismo: una esfera es ligeramente translúcida y desplazada, y la otra es completamente sólida. Los dos combinados imitan superficies reflectantes.

 <a-entity class="orb" data-> <lp-sphere seed="0" shadow max-amplitude="1 1 1" position="-0.5 0 -0.5"></lp-sphere> <lp-sphere seed="0" shadow max-amplitude="1 1 1" rotation="0 45 45" opacity="0.5" position="-0.5 0 -0.5"></lp-sphere> </a-entity>

Finalmente, gire la esfera indefinidamente agregando la siguiente etiqueta a-animation inmediatamente después de la lp-sphere dentro de la entidad .orb en la última instrucción.

 <a-animation attribute="rotation" repeat="indefinite" from="0 0 0" to="0 360 0" dur="5000"></a-animation>

Su código fuente para los envoltorios del orbe y el propio orbe deben coincidir exactamente con lo siguiente.

 <a-entity> <a-entity rotation="0 90 0" class="wrapper" position="0 0 0"> <a-entity class="container" position="8 3 0" scale="1 1 1"> <a-entity class="orb" data-> <lp-sphere seed="0" shadow max-amplitude="1 1 1" position="-0.5 0 -0.5"></lp-sphere> <lp-sphere seed="0" shadow max-amplitude="1 1 1" rotation="0 45 45" opacity="0.5" position="-0.5 0 -0.5"></lp-sphere> <a-animation attribute="rotation" repeat="indefinite" from="0 0 0" to="0 360 0" dur="5000"></a-animation> </a-entity> </a-entity> </a-entity> </a-entity>

Verifique que su código fuente coincida con el código fuente completo para el paso 3 en Github. Su vista previa ahora debería coincidir con lo siguiente.

Orbe giratorio y reflectante
(Vista previa grande)

A continuación, agregaremos más iluminación al orbe para obtener un tono dorado.

4. Ilumina el orbe

En este paso añadiremos dos luces, una de color y otra blanca. Esto produce el siguiente efecto.

Orbe iluminado con luces puntuales
(Vista previa grande)

Comience agregando la luz blanca para iluminar el objeto desde abajo. Usaremos un punto de luz. Directamente antes #orb0 pero dentro de #container-orb0 , agregue la siguiente luz de punto de compensación.

 <a-entity position="-2 -1 0"> <a-light distance="8" type="point" color="#FFF" intensity="0.8"></a-light> </a-entity>

En su vista previa, verá lo siguiente.

Orbe iluminado con punto de luz blanco
(Vista previa grande)

Por defecto, las luces no decaen con la distancia. Al agregar distance="8" , nos aseguramos de que la luz decaiga por completo con una distancia de 8 unidades, para evitar que la luz puntual ilumine toda la escena. A continuación, agregue la luz dorada. Agregue lo siguiente directamente encima de la última luz.

 <a-light class="light-orb" distance="8" type="point" color="#f90" intensity="1"></a-light>

Verifique que su código coincida exactamente con el código fuente del paso 4. Su vista previa ahora coincidirá con lo siguiente.

Orbe iluminado con luces puntuales
(Vista previa grande)

A continuación, realizará la modificación estética final del orbe y agregará anillos giratorios.

5. Agregar anillos

En este paso, producirá el orbe final, como se muestra a continuación.

Orbe dorado con múltiples anillos
(Vista previa grande)

Agregue un anillo en #container-orb0 directamente antes #orb0 .

 <a-ring color="#fff" material="side:double" position="0 0.5 0" radius-inner="1.9" radius-outer="2" opacity="0.25"></a-ring>

Tenga en cuenta que el anillo en sí no contiene color, ya que el color será imbuido por la luz del punto en el paso anterior. Además, el material="side:double" es importante ya que, sin él, la parte trasera del anillo no se renderizaría; esto significa que el anillo desaparecería durante la mitad de su rotación.

Sin embargo, la vista previa con solo el código anterior no se verá diferente. Esto se debe a que el anillo está actualmente perpendicular a la pantalla. Por lo tanto, solo se ve el "lado" del anillo (que tiene un grosor 0). Coloque la siguiente animación entre las etiquetas a-ring A en la instrucción anterior.

 <a-animation attribute="rotation" easing="linear" repeat="indefinite" from="0 0 0" to="0 360 0" dur="8000"></a-animation>

Su vista previa ahora debería coincidir con lo siguiente:

Orbe dorado con anillo
(Vista previa grande)

Crea un número variable de anillos con diferentes ejes de rotación, velocidades y tamaños. Puede utilizar los siguientes anillos de ejemplo. Cualquier anillo nuevo debe colocarse debajo del último a-ring

 <a-ring color="#fff" material="side:double" position="0 0.5 0" radius-inner="2.4" radius-outer="2.5" opacity="0.25"> <a-animation attribute="rotation" easing="linear" repeat="indefinite" from="0 45 0" to="360 45 0" dur="8000"></a-animation> </a-ring> <a-ring color="#fff" material="side:double" position="0 0.5 0" radius-inner="1.4" radius-outer="1.5" opacity="0.25"> <a-animation attribute="rotation" easing="linear" repeat="indefinite" from="0 -60 0" to="-360 -60 0" dur="3000"></a-animation> </a-ring>

Su vista previa ahora coincidirá con lo siguiente.

Orbe dorado con múltiples anillos
(Vista previa grande)

Verifique que su código coincida con el código fuente del paso 5 en Github. Esto concluye la decoración del orbe. Con el orbe terminado, a continuación agregaremos interactividad al orbe. En el siguiente paso, agregaremos específicamente un cursor visible con una animación de clic cuando apunte a objetos en los que se puede hacer clic.

Hacer que los orbes sean interactivos

6. Agregar un cursor

En este paso, agregaremos un cursor blanco que puede activar objetos en los que se puede hacer clic. El cursor se muestra a continuación.

haciendo clic en el orbe
(Vista previa grande)

En su etiqueta a-camera , agregue la siguiente entidad. El atributo fuse le permite a esta entidad la capacidad de desencadenar eventos de clic. El atributo raycaster determina con qué frecuencia y en qué medida comprobar los objetos en los que se puede hacer clic. El atributo de objects acepta un selector para determinar en qué entidades se puede hacer clic. En este caso, se puede hacer clic en todos los objetos de la clase clickable .

 <a-entity cursor="fuse: true; fuseTimeout: 250" position="0 0 -1" geometry="primitive: ring; radiusInner: 0.03; radiusOuter: 0.04" material="color: white; shader: flat; opacity: 0.5" scale="0.5 0.5 0.5" raycaster="far: 20; interval: 1000; objects: .clickable"> <!-- Place cursor animation here --> </a-entity>

A continuación, agregue la animación del cursor y un anillo adicional para la estética. Coloque lo siguiente dentro del objeto de cursor de entidad de arriba. Esto agrega animación al objeto del cursor para que los clics sean visibles.

 <a-circle radius="0.01" color="#FFF" opacity="0.5" material="shader: flat"></a-circle> <a-animation begin="fusing" easing="ease-in" attribute="scale" fill="backwards" from="1 1 1" to="0.2 0.2 0.2" dur="250"></a-animation>

A continuación, agregue la clase en la que se clickable a #orb0 para que coincida con lo siguiente.

 <a-entity class="orb clickable" data->

Verifique que su código coincida con el código fuente del Paso 6 en Github. En su vista previa, arrastre el cursor fuera de ellos hacia el orbe para ver la animación de clic en acción. Esto se muestra a continuación.

haciendo clic en el orbe
(Vista previa grande)

Tenga en cuenta que el atributo en el que se puede hacer clic se agregó al propio orbe y no al contenedor del orbe. Esto es para evitar que los anillos se conviertan en objetos en los que se pueda hacer clic. De esta forma, el usuario debe hacer clic en las esferas que forman el propio orbe.

En nuestro paso final de esta parte, agregará una animación para controlar los estados de encendido y apagado del orbe.

7. Agregar estados de orbe

En este paso, animarás el orbe dentro y fuera del estado al hacer clic. Esto se muestra a continuación.

Orbe interactivo que responde a los clics
(Vista previa grande)

Para empezar, encogerás y bajarás el orbe al suelo. Agregue etiquetas a-animation al #container-orb0 justo después de #orb0 . Ambas animaciones se activan con un clic y comparten la misma función ease-elastic suave para un ligero rebote.

 <a-animation class="animation-scale" easing="ease-elastic" begin="click" attribute="scale" from="0.5 0.5 0.5" to="1 1 1" direction="alternate" dur="2000"></a-animation> <a-animation class="animation-position" easing="ease-elastic" begin="click" attribute="position" from="8 0.5 0" to="8 3 0" direction="alternate" dur="2000"></a-animation>

Para enfatizar aún más el estado apagado, eliminaremos la luz del punto dorado cuando el orbe esté apagado. Sin embargo, las luces del orbe se colocan fuera del objeto del orbe. Por lo tanto, el evento de clic no pasa a las luces cuando se hace clic en el orbe. Para sortear este problema, usaremos Javascript ligero para pasar el evento de clic a la luz. Coloque la siguiente etiqueta de animación en #light-orb0 . La luz se activa mediante un evento de switch personalizado.

 <a-animation class="animation-intensity" begin="switch" attribute="intensity" from="0" to="1" direction="alternate"></a-animation>

A continuación, agregue el siguiente detector de eventos de clic al #container-orb0 . Esto transmitirá los clics a las luces del orbe.

 <a-entity ...>

Verifique que su código coincida con el código fuente del Paso 7 en Github. Finalmente, abra su vista previa y mueva el cursor dentro y fuera del orbe para alternar entre los estados de encendido y apagado. Esto se muestra a continuación.

Orbe interactivo que responde a los clics
(Vista previa grande)

Esto concluye la interactividad del orbe. El jugador ahora puede encender y apagar los orbes a voluntad, con estados de encendido y apagado que se explican por sí mismos.

Conclusión

En este tutorial, construyó un orbe simple con estados de encendido y apagado, que se puede alternar con un clic de cursor compatible con auriculares VR. Con varias técnicas de iluminación y animaciones diferentes, pudo distinguir entre los dos estados. Esto concluye los elementos de diseño de realidad virtual para los orbes. En la siguiente parte del tutorial, llenaremos los orbes dinámicamente, agregaremos mecánicas de juego y configuraremos un protocolo de comunicación entre un par de jugadores.