Este documento explora soluciones y consideraciones relacionadas con la detención de la reproducción de animaciones, particularmente en el contexto de Blender y su integración con A-Frame para realidad virtual. Aborda desafíos comunes y ofrece estrategias para superarlos.

Introducción a la Realidad Virtual y A-Frame
Muchos reflexionarán sobre la utilidad de la realidad virtual, algunos a favor y otros en contra, pero hay algo muy claro cuando vemos la facilidad con la que nuestro compañero Enrique Rubio presenta el framework A-Frame, y es que tenemos que poner a prueba la madurez de su desarrollo.
Para nuestro objetivo, no nos iremos muy lejos; volveremos al clásico dungeon/mazmorra donde, por arte de cursor, haremos frente a enemigos estáticos y poco animados.
AVISO: he experimentado muchos problemas en navegadores Chrome en varios ordenadores, aunque en mi teléfono Android con Chrome sí funciona. Esto incluyó desde problemas con las colisiones hasta la imposibilidad de cargar la escena.
Inspector de A-Frame: Creación y Visualización de Escenas
El inspector de A-Frame, como su nombre indica, nos permite ver y crear gráficamente escenas de A-Frame.
Instalación y Estructura
Para instalarlo en local, es tan sencillo como ir a su repositorio en GitHub y clonarlo donde queramos.
Desde el principio podemos observar la estructura de la escena en la parte izquierda de la ventana. Aquí podemos crear nuevas entidades o seleccionarlas. Como ya podéis haber visto, tenemos el editor gráfico donde es representada toda la escena con sus texturas correspondientes. Finalmente, y no menos importante, si hacemos clic sobre alguna entidad, nos aparecerá a la derecha un menú con todas las propiedades de dicha entidad.

Preparación de un Minijuego en A-Frame
Una vez que hemos visto el inspector, ya podemos comenzar a crear nuestro minijuego. Una vez tenemos claros nuestros objetivos, pasamos a prepararlo todo.
Para ello, según hemos visto anteriormente, iniciaremos el inspector de A-Frame y usaremos el ejemplo que nos aporta como base; así podremos hacer nuestros experimentos y probarlos en una escena ya creada y que tenemos la certeza de que funciona. También podemos duplicar la carpeta «examples» que se encuentra en el inspector (que es el proyecto de ejemplo) y le cambiamos el nombre; de esta manera podremos modificar el nuevo proyecto copiado del ejemplo y tener el ejemplo original intacto. Otra opción es crear una nueva carpeta y empezar un proyecto desde cero, pero hay que tener en cuenta que los proyectos tienen que encontrarse dentro de nuestra carpeta del inspector.
Puede ocurrir, y en mi caso ocurrió, que el inspector o la aplicación de A-Frame que queramos iniciar con el comando «npm start» no funcione, haciendo que en la consola nos salgan errores.
Integración de Modelos 3D (Blender) y Texturas
Algunos quizás ya sepan que es necesario exportar nuestro fantasma y muchas herramientas nos permiten hacerlo a varios formatos. Aprovechando el inspector, añadiremos el modelo y sus texturas mediante este.
Comenzaremos abriendo el inspector -en caso de que no lo tengamos ya- pulsando «Ctrl+Alt+I» y creando una nueva entidad (arriba a la izquierda del inspector encontramos un «+» para crearla). Con el componente OBJ-Model podemos añadir un archivo MTL y un OBJ, así que en una carpeta llamada «resources», que crearemos dentro de nuestro proyecto en caso de que no exista, meteremos el OBJ del modelo que hemos creado y lo referenciaremos en el componente de la entidad escribiendo «resources/ghost.obj».
Esto debería hacer visible en el inspector, en la posición donde se encuentre la entidad, a nuestro fantasma, pero sin textura y de un tamaño gigantesco, cosa que solucionamos variando su escala a 0.1. Finalmente ya tendremos nuestro fantasma con modelo y texturas propiamente aplicadas. Cabe destacar que no hemos añadido el archivo MTL, ya que no lo coge bien, quitando la textura. La aplicación de los distintos archivos dependerá muy probablemente del programa que los ha exportado, ya que es posible que los que uséis Blender sí tengáis que añadir el MTL.
Una vez copiado, pegaremos el código en nuestro index.html, que será el que tenga todo el código HTML. He aprovechado también para cambiar la escena de tal forma que he añadido muros (entidad con forma de box o caja) con texturas y he cambiado la textura y la forma del suelo para asemejarlo un poco más con los muros. Aunque por el momento podamos atravesar los muros, lo resolveremos más adelante. La luz también la modifiqué, pero realmente configurarla a vuestro gusto.

Animación Básica de Entidades
Ya que tenemos un fantasma, vamos a hacer que este suba y baje un poco para que dé la sensación de levitación. Esta vez vamos a hacerlo a mano, sobre el index.html, añadiendo dentro de nuestra entidad con ID «Ghost01» un tag con el cual especificaremos que la posición B sea un poco más arriba de su posición original. Con el atributo repeat especificamos que nunca acabe, con direction="alternate-reverse" especificamos que sea de ida y vuelta (de A a B y de vuelta a A) y el easing nos permite decir cómo va a ser ese movimiento, en nuestro caso, lineal.
Movimiento del Usuario en VR
Habiendo visto cómo podemos hacer que una entidad se mueva, viene el siguiente paso: ¿cómo se moverá el usuario? Esto, sin duda alguna y por el momento, es un problema muy serio de la realidad virtual, ya que solo las gafas (que sin contar Cardboard no es que sean baratas actualmente) no nos permiten movernos. Los controles WASD ya vienen incluidos en la cámara de ejemplo, que además viene con un cursor y un raycaster para poder interactuar con otras identidades.
Mediante este código podemos aprender varias cosas. Todo componente tiene un nombre, en este caso es «static-movement». El «schema» es una lista con las propiedades del componente que pueden tener especificados valores por defecto. En nuestro caso, «init» es un método que especifica lo que se realiza al crearse la entidad que tiene el componente añadido. El objeto «el» es la entidad y a esa entidad le añadimos el listener que, como observamos, obtenemos, como en HTML, la cámara con ID «player» y editamos su posición para que esta sea la de la entidad que tiene el componente asociado.
Ahora que tenemos el componente creado lo guardamos como «movement.js» y lo añadimos en nuestro index.html. Si lo probáis veréis que nos teletransporta, pero… ¡no nos deja en el suelo!
Sistema de Combate y UI
Tenemos un fantasma y unas esferas que nos permiten movernos por el mapa, pero ¿cómo lo matamos? Aquí entra en juego el sistema de «combate», en el que hacemos daño al fantasma para matarlo y el fantasma nos responde quitándonos vida. Para el fantasma crearemos tres botones (Atacar, Defender y Evadir) y una interfaz para mostrar la vida del fantasma. Para ello crearemos entidades de texto y, ya que no todo lo que ocupe dicho texto es clickable, añadiremos por cada texto un plano que los dote de mayor visibilidad de un área completamente clickable. Como la interfaz de la vida se encuentra «dentro» de la cámara (el usuario), esto hace que su posición sea relativa a la de la cámara, fijándose así en la pantalla del usuario.
Lógica del Enemigo y Bucle de Actualización
Tenemos interfaz, pero ahora queda darle vida. Para comenzar crearemos el archivo «enemy.js» y lo añadiremos al index de nuestro proyecto. También es destacable la función "tick", que se ejecuta en cada frame, con lo cual se ejecuta constantemente.
Manejo de Audio y Problemas Comunes
Leyendo en páginas de internet se ve que hay problemas con el sonido, que no se reproduce o cosas así. Principalmente se refieren a atributos de "sound" como el autoplay. En mi caso surgió un ¿bug? Añadiremos una música de fondo para dar algo de ambiente y un efectillo para cuando nos demos de tortas con un enemigo.
La música que empleo de fondo la podéis encontrar
Música Ambiente para Jugar al Catan | Background Music to Play Catan
Música Ambiente para Jugar al Catan | Background Music to Play Catan
Ahora viene el efecto de sonido que se reproducirá cuando ataquemos al fantasma. Para ello realizaremos lo mismo que para la música de fondo, pero esta vez no pondremos ni loop ni autoplay, ya que lo controlaremos mediante JavaScript. Sí, hay que volver a duplicar la entidad del sonido, cosa que me parece muy molesta ya que es innecesario.
Colisiones y Sistema de Físicas
Hemos avanzado mucho, hasta el punto de tener algo jugable, en donde podemos matar a enemigos repartidos por un mapa sin necesidad de tener piernas. Aunque para los que no usan teclado realmente no debería implicar nada (¿cómo vas a atravesar una pared si no puedes moverte?), esto es un problema en caso de alguien que pueda moverse.
Lo resolveremos creando colisiones y para ello emplearemos los componentes Aframe-extras y aframe-physics-system o sistema de físicas. Para poder usar este componente simplemente descargamos la versión minificada y la añadimos como cualquier archivo JavaScript.
A continuación, para el resto de entidades añadiremos el componente static-body, el cual por defecto elige automáticamente la mejor forma para su "caja" de colisiones. Si habéis probado la escena solo habiendo añadido el componente "kinematic-body", veréis como caéis al infinito, ya que ni siquiera el suelo es considerado sólido, y al haber gravedad la cámara ya no flota "por arte de magia". Para el suelo y las paredes simplemente hay que añadir el atributo "static-body" (de aframe-physics-system), no es necesario especificar nada más.
Si queremos ver que funciona y cómo son las cajas de colisiones, tendremos que añadir el atributo physics="debug: true". Ahora ya sí que estamos encerrados entre los muros que hemos creado, con un fantasma delante que podemos matar, ¿o no? Si añadimos "static-body" a nuestro simpático fantasma veremos cómo de forma automática elige "box" como forma y el cálculo de esta caja es erróneo, ya que solo rodea a la interfaz.
Para solucionar este problema de cálculo añadiremos una caja que colocaremos detrás del fantasma, pero que este la incluya, para que la caja de colisiones se calcule para incluir tanto a toda su interfaz como a dicha caja, creando una caja de colisiones que engloba todo, incluido al fantasma.

Limitaciones y Posibilidades de A-Frame en Animación
Como hemos estado viendo a lo largo de este tutorial, las posibilidades que nos ofrece A-Frame son, como mínimo, decentes. Uno de los principales inconvenientes, que espero que amplíen, son las animaciones. Las animaciones son algo básicas, fáciles de usar para algo simple pero no para tareas más sofisticadas.
Un ejemplo lo encontraríamos a la hora de hacer que nuestro fantasma se moviera; si queremos que levite y se mueva a la vez nos resulta imposible ya que sólo se ejecuta una animación simultáneamente, habría que moverlo según un vector que sea la combinación de ambos movimientos, cosa que complica la tarea. Aunque lo anterior se base en mi experiencia, no es absoluto. A-Frame es flexible y nos permite realizar cualquier idea rápidamente, aunque tenga sus posibles inconvenientes.