Publicado por

As above, so below

Sea of Clouds

«Sea of Clouds»es el nombre de mi prototipo para la tercera Práctica de Evaluación Continua (PEC3) de la asignatura Programación de Videojuegos 3D del Máster Universitario en Diseño y Programación de Videojuegos de la UOC.

El objetivo de la práctica era desarrollar un juego de plataformas en tercera persona utilizando los conocimientos adquiridos en el estudio del primer módulo de la asignatura y realizando investigación por cuenta propia.

Vídeo explicativo

Repositorio en GitLab

UOC – M7.458 – PEC3 en GitLab

Versión de Unity

La versión de Unity utilizada para el desarrollo de la práctica es la 2021.3.19f1 LTS.

El orden de las escenas está definido en los builds settings del proyecto, siendo Assets/Scenes/Opening.scene la primera escena que debe cargarse.

Cómo jugar

El objetivo del juego es conseguir tres llaves mientras se esquiva a hordas de monstruos. Una vez conseguidas las tres llaves, aparece un enemigo mayor cuya derrota es el objetivo final del juego.

El control se lleva a cabo mediante teclado y ratón, aunque también está preparado para ser compatible con gamepad:

  • Las letras WASD mueven al personaje.
  • El Espacio hace que el personaje salte.
  • La tecla Mayúsculas izquierda sirve para que el personaje esprinte.
  • El botón derecho del ratón apunta el arco.
  • El botón izquierdo del ratón dispara el arco.
  • El botón central del ratón realiza un ataque cuerpo a cuerpo.
  • La tecla Escape sirve para pausar el juego y abrir el menú de pausa.

Desarrollo

De cara a completar el desarrollo de la práctica, se han llevado a cabo las siguientes tareas obligatorias y opcionales, además de incluir algunos extras que se han ido añadiendo a lo largo del desarrollo.

  • ✅ (Obligatorio) Se ha creado un escenario que consiste en un pueblo y una zona natural.
  • ✅ (Obligatorio) El personaje dispone de un arma a distancia que le permite disparar hacia delante.
  • ✅ (Obligatorio) El personaje está completamente animado.
  • ✅❗ (Obligatorio) La salud y la armadura se muestran constantemente en el HUD. La munición, no (ver explicación más adelante).
  • ✅ (Obligatorio) Los enemigos pasean por la ciudad y atacan al enemigo cuando está cerca.
  • ✅ (Obligatorio) Los enemigos están completamente animados.
  • ✅ (Obligatorio) Se dispara un sistema de partículas cuando un personaje (jugador o no) recibe daño o muere.
  • ✅❗ (Obligatorio) Hay objetos de salud y armadura repartidos por el escenario. Munición, no (ver explicación más adelante).
  • ✅ (Obligatorio) El juego dispone de una pantalla de juego terminado que permite reiniciar la partida.
  • ✅ (Opcional) El juego dispone de al menos un puzle que requiere saltar para progresar.
  • ❌ (Opcional) No se han añadido otros tipos de arma (ver explicación más adelante).
  • ✅ (Opcional) El juego está totalmente sonificado.
  • ✅ (Opcional) Se han añadido diferentes tipos de enemigos.
  • ✅ (Opcional) Es posible apuntar al disparar.
  • ✅ (Opcional) El juego dispone de al menos un puzle que requiere obtener llaves para progresar.
  • ✅ (Opcional) El jugador tiene un arma cuerpo a cuerpo.
  • ✅ (Opcional) Los enemigos pueden dejar objetos al morir.
  • ✅ (Opcional) Los enemigos aparecen en varias fuentes del escenario de manera incremental.
  • ✅ (Opcional) Se ha utilizado el componente animation rigging para que el personaje mire hacia los objetos cercanos.
  • ✅ (Opcional) Se ha implementado la iluminación global

Todos los objetivos que no se han cumplido o se han cumplido parcialmente están relacionados con la inclusión de nuevas armas o con la munición y es porque el proyecto se ha considerado como un todo que incluye los objetivos de esta práctica y de la siguiente y, por un motivo puramente arquitectónico y de optimización del proceso de desarrollo, se ha optado por implementar primero las características con mayor transversalidad y por posponer aquellas que son fácilmente incorporables como extras. En concreto, se ha priorizado la implementación de la IA en los personajes, afrontando las siguientes tareas de la próxima práctica:

  • ✅ (Obligatorio) Los enemigos se mueven entre puntos aleatorios y corren hacia el jugador al detectarlo.
  • ✅ (Obligatorio) Hay personajes de carácter neutral paseando por el escenario.
  • ✅ (Obligatorio) Los personajes de carácter neutral huyen de los enemigos.
  • ✅ (Opcional) Los personajes de carácter neutral se convierten en enemigos al morir a manos de un enemigo.

La escena de juego

La escena de juego no es propia. Ha sido extraída del paquete gratuito RPG Poly Pack – Lite de la Unity Assets Store y adaptado según lo requerido por la práctica. Entre otras adaptaciones, se han aplicado shaders a todas las texturas, tanto del escenario como de los personajes y los objetos, aplicando cel shading y un delineado grueso para dar un aspecto de dibujo animado.

Como tal, la escena dispone de una pequeña aldea en la que se desarrolla el juego y un entorno forestal sin mucho más que unos pocos objetos y enemigos repartidos, pero que ofrece la ventaja de poder huir de los enemigos si las cosas se tuercen.

Apuntado, disparo y ataque cuerpo a cuerpo

Para poder disparar el arco, es necesario cargarlo primero. Al hacerlo, el juego bloquea el movimiento del jugador para que no pueda girar con las flechas (sólo desplazarse lateralmente) y enfoca la visión utilizando una segunda cámara. Además, permite apuntar de manera libre a cualquier punto de la escena.

El HUD

Como en el caso de la práctica anterior, la interfaz de usuario muestra en todo momento la salud y el escudo del jugador, así como las llaves que ha conseguido. También muestra la cruceta y los mensajes enviados por el juego.

Tipos de personaje

A efectos de gestionar de manera transversal las características comunes entre jugador, enemigos y NPC, se ha creado una clase maestra que contiene las propiedades y métodos compartidos y que se apoya en una máquina de estados para manejar el tipo del jugador. Esta aproximación permite, entre otras cosas, poder cambiar fácilmente de tipo a un personaje y se implementa cuando un NPC neutral o aliado se convierte en enemigo al morir. E incluso permitiría al jugador controlar a un NPC o a un enemigo, así como a cualquier otra entidad a la que se extienda la clase.

Se han incluido los tipos siguientes:

  • Player. En este estado, se desactivan las automatizaciones y se activan el character controller y el resto de componentes necesarios para poder jugar.
  • Enemy. En este estado, el personaje deambula por la escena y ataca al jugador y a los NPC neutrales y aliados cuando pasan cerca.
  • Boss. En este estado, el personaje se comporta igual que un enemigo, pero añade la lógica de finalización del juego al derrotarlo.
  • Neutral. En este estado, el personaje deambula por la escena y huye cuando un enemigo pasa cerca.
  • Ally. En este estado, el personaje deambula por la escena y ataca a los enemigos que pasan cerca.

En el caso de los enemigos y los NPC (neutrales y aliados) se han añadido varios tipos con modelos y características diferentes (velocidad, daño, resistencia, etc.).

Objetos y llaves

Como en la práctica anterior, el juego incluye tanto objetos de curación como llaves repartidas por el escenario o dejadas por los enemigos al morir.

Animaciones y rigging

Todos los personajes están completamente disponen de animaciones para todas las posibles combinaciones, aunque no las utilicen, precisamente por la posibilidad de que cualquiera de ellos cambie de tipo. Además, se usan capas y animation events para poder controlar de manera fácil desde el código los momentos en los que se produce algún factor de interés en la reproducción de la animación.

También se ha implementado el animation rigging para el jugador, principalmente para hacer que tanto la cabeza como el torso del personaje miren suavemente hacia los objetos que tienen cerca, pero también para asegurar que el arco mira en todo momento a la posición correcta cuando se está apuntando.

Sistemas de partículas

Se han implementado partículas para un gran número de acciones: al ser golpeado, al morir, al recuperar salud, al convertirse en enemigo, etc.

Inteligencia artificial

Para implementar los objetivos relacionados con la inteligencia artificial, se utiliza una mezcla de NavMesh y de detección de colisiones. Todos los personajes disponen de tres maneras de detectar colisiones: con el collider incorporado al modelo a través del player controller o del capsule collider, con un trigger en un una esfera con un radio de cuatro metros (esfera interna) y por otra con un radio de siete metros (esfera externa). Además, disponen del componente NavMeshAgent para poder navegar por el terreno de manera autómoma.

Teniendo eso en cuenta, el flujo de un personaje normalmente es:

  1. En su estado inicial, a falta de objetivos, el personaje deambula por el escenario desplazándose entre puntos aleatorios con NavMesh.
  2. Cuando otro personaje entra en su esfera interna, lo añade a una lista de objetivos que utiliza para escapar (NPC neutral) o para saber a qué atacar (NPC Aliado, Enemigo y Enemigo final).
  3. Además, si el personaje es atacado por cualquier otro personaje, lo define directamente como objetivo forzado, independientemente de si está o no dentro del rango de detección.
  4. Mientras la lista contiene objetivos, el personaje comprueba qué personaje es el que está más cerca y en base a ello fija un punto de origen del cuál huir (NPC neutral) o fija un punto de destino para atacar (NPC Aliado, Enemigo y Enemigo final).
  5. Si el personaje alcanza a su objetivo, ataca siempre y cuando no exista una determinada distancia entre ambos.
  6. Cuando un objetivo sale de la esfera externa, el personaje lo elimina de la lista de personajes y deja de perseguirlo.
  7. Si la lista de objetivos se vacía, el personaje vuelve a deambular por el escenario.

 

Iluminación global

Finalmente, se ha hecho uso de la iluminación global y el baking para optimizar el uso de la iluminación en la escena de juego y mejorar el rendimiento general.

 

Problemas conocidos

En el momento de la entrega, se conocen los siguientes problemas:

  • Los sistemas de partículas asociados a los personajes y objetos se están renderizando por detrás de los elementos del terreno.
  • En la misma línea, las olas del agua que rodea la isla se reflejan en los personajes y enemigos repartidos por la escena.
  • Faltan sonidos para varios de los tipos de personajes.
  • El agua que rodea la isla no dispone de zona de muerte, por lo que es salir de la escena si se cae en ella.

Créditos

Paquetes completos

Fuentes

Música

Shaders

Sonidos

Referencias

C# – General

Unity – General

Animaciones – General

Animaciones – Interrupción

Animaciones – Rigging

Cinemachine

Iluminación

NavMesh

Shaders

Debate1en As above, so below

  1. Anna Zango Palau says:

    Como siempre, me encanta tu juego Salva! Me parece que has puesto una outline a los personajes con un Shader para que resalten, no? En plan cartoon, queda genial!! Por cierto, tus enemigos me parecen monísimos jajaja.

    También me parece muy buena idea como has planteado las tareas. Con perspectiva, debería haberlo hecho igual, porque ahora tendré que cambiar cosas de zero porque no las diseñé pensando en lo que haría falta. Muy buena planificación Salva!!

Deja un comentario