Se hará una introducción de la funcionalidad implementada en este motor y se mostrará en video un uso básico.

Workflow básico

A continuación se presenta un video que muestra el proceso de crear un escenario con el editor, añadir los recursos generados al motor y compilar con Android Studio.


Introducción

Actualmente existe una amplia variedad de motores gratuitos y de pago que agilizan el desarrollo de videojuegos, por lo que hacer hoy día uno propio sería poco menos que un suicidio a nivel empresarial, sobre todo si la publicación de videojuegos fuese mi único sustento. Emprender este proyecto tuvo dos objetivos principales: aprender sobre el funcionamiento interno de los motores actuales y presentarlo para el Trabajo de fin de grado. Ni que decir tiene que este motor no fue completado al 100% debido al tiempo que dediqué (unas 660 horas), pero si me esforcé en tocar varias disciplinas en su desarrollo, tales como la computación gráfica con OpenGL; la inteligencia artificial, de la que usé patrones sencillos de pathfinding; o el uso de sensores, algo habitual en el desarrollo móvil.

En definitiva, si tuviera que definir el proyecto en unas pocas líneas, diría que es un software que simplifica el desarrollo de videojuegos en dos dimensiones para Android, aportando una interfaz gráfica sencilla para el diseño de niveles y una interfaz basada en documentos XML para implementar las mecánicas de juego.

Funcionalidad

Actores

  • Diseño de actores orientado a Sprites. Todo lo que se ve en el juego es de tipo Sprite. Un Sprite es un contenedor de funcionalidad inicialmente vacío y ampliable mediante el uso de módulos.
  • Diseño modular. Cada módulo añade entidad o funcionalidad a un Sprite, de manera que cada actor solo usa los módulos que necesita para funcionar correctamente.
  • Definición de Sprites en XML. Definición del Sprite en sí mismo y los módulos que contiene como etiquetas XML.
  • Listado de módulos:
    • Animación. Posiblidad de añadir animaciones frame by frame a un actor.
    • Imagen. Si el Sprite contiene este módulo, implica que puede ser dibujado en pantalla.
    • Posición relativa. La posición del actor puede ser relativa al suelo del escenario o a la cámara.
    • Pulsable. El actor reacciona ante la interacción táctil del usuario con la pantalla.
    • Desplazamiento. El actor puede desplazarse por el escenario o por la pantalla, según su posición relativa.
    • Inteligencia artificial. El actor puede ser controlado por una inteligencia artificial. Con ella, pueden definirse rutas de movimiento del actor, e incluso puede esquivar obstáculos (estáticos y dinámicos) para alcanzar su destino.
    • Jugador. Con este módulo, el usuario puede controlar al actor.
    • Sonido. El actor emite sonido sincronizado con alguna animación, como por ejemplo, la animación de caminar genera sonido de pasos.
    • Tangible. El actor genera colisiones al interactuar con otros actores colisionables.
    • Texto. El actor puede contener texto.

Un ejemplo de definición de Sprites:

<sprite name="prota">
    <tangible value="true"/>
    <cuadrante alto="1" ancho="1" squareY="16" squareX="10"/>
    <bitmap default-height="77" default-width="47" defaultY="0" defaultX="0" height="2" width="1" frameY="-1" frameX="0" draw-layer="capa-suelo" gr-component="myImage"/>
    <motion-character orientation="default"/>
    <animation resource="human_playable"/>
    <sound/>
    <movementAI/>
    <clickable touchType="down"/>
    <playable/>
</sprite>

Cámara

  • Perspectiva dimétrica. La cámara se presenta en esta perspectiva, y aunque puede desplazarse por el escenario y hacer zoom, no puede realizar rotaciones de ningún tipo.
  • Función de seguimiento. La cámara puede seguir a cualquier Sprite.
  • Desplazarse a un punto. Se puede hacer un plano en cualquier área del escenario haciendo un barrido hasta llegar a la zona o de forma inmediata.
  • Cámara libre. El objetivo en este modo se desplazará por el escenario en función de los valores del giroscopio del dispositivo móvil. Si el teléfono no incluye este sensor, la función dejará la cámara en modo ocioso.
  • Zoom logarítmico. La cámara hará un acercamiento rápido al escenario a una velocidad que cambia de forma logarítmica.
  • Terremoto. La cámara se agitará, provocando además una vibración en el teléfono móvil.

Suelo

  • Tesela cuadrada. El suelo del juego se presenta como una cuadrícula de tamaño variable donde cada baldosa contiene 3 tipos de información: imagen del suelo, sonido que emite cuando algún actor pasa sobre ella y tangibilidad, que admite (o no) colisiones por parte de los actores.
  • Animación. Las imágenes del suelo (podríamos decir, los objetos que se encuentran a ras de suelo) pueden tener animaciones de hasta 3 frames. Esto es muy útil, por ejemplo, para animar el agua.

Mecánicas de juego

  • Diseño basado en acción-reacción. Cada elemento Event-Action representa un conjunto de sucesos (acciones) que ocurren cuando un conjunto de eventos tienen lugar previamente. Todos los eventos deben activarse en el mismo momento para que todas las acciones tengan lugar. Cada acción puede ejecutarse en paralelo o secuencialmente a la acción que la precede, previa configuración.
  • Listado de eventos:
    • Pulsación de baldosa. El usuario ha pulsado sobre una baldosa vacía en el escenario.
    • El Sprite está en la baldosa. Se activa cuando un actor concreto se encuentra situado en una baldosa concreta.
    • El Sprite se está moviendo. Evento que se activa cuando un actor comienza a moverse.
    • Sprite orientado. Se activa cuando el actor está mirando hacia la orientación indicada.
    • El Sprite está enfocado. El actor se encuentra en los límites de la cámara, y por tanto, está visible para el usuario.
    • El Sprite está parando. El actor se estaba moviendo y ha comenzado a detenerse.
    • Pulsación de Sprite. El usuario ha pulsado sobre un actor concreto. Este evento tiene preferencia sobre el evento de pulsación de baldosa.
    • El Sprite está cerca de otro Sprite. Se activa cuando un actor concreto está a una distancia concreta (medida en baldosas) de otro actor específico.
  • Listado de acciones:
    • Movimiento. Ordena el movimiento de un actor a una baldosa concreta o de forma relativa a su posición actual.
    • Activar función de cámara. Activa alguna de las funciones disponibles de la cámara, descritas en un punto anterior.
    • Orden de ruta. Ordena a un actor a desplazarse por el escenario usando una ruta cargada previamente.
    • Activar o desactivar otro Event-Action.
    • Cargar o descargar archivo XML con Event-action. Cuando se cambia de área, puede cambiar lo que ocurre en ella, por ello se pueden cargar y descargar mecánicas de juego.
    • cargar ruta. Permite la carga o descarga de una ruta de inteligencia artificial, definida también en XML.
    • Cargar escenario. Carga el suelo y los actores estáticos de una zona del juego concreta. Este escenario está definido en XML, y es generado por el editor de escenarios mostrado en el video.
    • Activar animación en Sprite.
    • Mostrar u ocultar texto.
    • Carga de Sprite. Carga un actor o un grupo de ellos al margen de los Sprites cargados en el escenario. Sirve para cargar personajes y otros actores que no pertenecen a un escenario en concreto.

Interfaz XML

  • Un videojuego se define en su totalidad en XML.
  • Defnición de animaciones. Se indican los frames que van a participar en la animación, los tiempos de espera entre frames y, opcionalmente se indica un índice a un sonido si el frame lo emite al mostrarse en pantalla. Ejemplo:
     <?xml version="1.0" encoding="UTF-8"?>
    <animationDocument>
        <default-frame sound="-1" bitmap-height="100" bitmap-width="80" bitmap-coord-Y="360" bitmap-coord-X="0" sprite-height="5" sprite-width="4" sprite-coord-Y="-3" sprite-coord-X="-1"/>
        <animation-list>
            <default-animation>
                <frame sound="-1" bitmap-height="100" bitmap-width="80" bitmap-coord-Y="360" bitmap-coord-X="0" sprite-height="5" sprite-width="4" sprite-coord-Y="-3" sprite-coord-X="-1"/>
                <frame sound="-1" bitmap-height="100" bitmap-width="80" bitmap-coord-Y="360" bitmap-coord-X="80" sprite-height="5" sprite-width="4" sprite-coord-Y="-3" sprite-coord-X="-1"/>
                <frame sound="-1" bitmap-height="100" bitmap-width="80" bitmap-coord-Y="360" bitmap-coord-X="160" sprite-height="5" sprite-width="4" sprite-coord-Y="-3" sprite-coord-X="-1"/>
                <frame sound="-1" bitmap-height="100" bitmap-width="80" bitmap-coord-Y="360" bitmap-coord-X="80" sprite-height="5" sprite-width="4" sprite-coord-Y="-3" sprite-coord-X="-1"/>
                <wait-time time="250000000"/>
                <wait-time time="250000000"/>
                <wait-time time="250000000"/>
                <wait-time time="250000000"/>
            </default-animation>
        </animation-list>
        <sound-list> </sound-list>
    </animationDocument>
    
  • Eventos y acciones. El sistema de mecánicas se define en XML uniendo eventos y acciones en contenedores llamados Event-action. Ejemplo:
     <?xml version="1.0" encoding="UTF-8"?>
    <event-actions>
        <event-action enabled="true" num-times="-1" id="5">
            <eve-sprite-oriented orientation="south" sprite-name="0"/>
            <eve-sprite-moving sprite-name="0"/>
            <eve-sprite-walking sprite-name="0" walk-run="walk"/>
            <act-start-animation num-times="-1" sprite-name="0" end-frame="origin" animation-name="walk-south" concurrent="true"/>
        </event-action>
    </event-actions>
  • Rutas. Pueden definirse rutas fijas para los actores controlados por inteligencia artificial. Ejemplo:
    <?xml version="1.0" encoding="UTF-8"?>
    <route loop="true">
        <absolute-order wait-after-reach="3000000000" algorithm="a-star" squareY="15" squareX="10"/>
        <relative-order wait-after-reach="3000000000" algorithm="stupid-persistent" num-squares="5" orientation="north"/>
        <relative-order wait-after-reach="0" algorithm="stupid-lazy" num-squares="15" orientation="east"/>
        <relative-order wait-after-reach="7000000000" algorithm="a-star" num-squares="15" orientation="south"/>
    </route>
  • Conversaciones. El motor permite configurar conversaciones fácilmente mediante el uso de esta interfaz en XML. En el siguiente ejemplo verás que la frase en sí misma no aparece por el XML. Esto es debido a que Android ya contiene un sistema de ficheros en el que colocar las frases para facilitar su traducción a otros idiomas en función del idioma del teléfono:
    <?xml version="1.0" encoding="UTF-8"?>
    <conversation>
        <sentence phrase="phrase1" name="Pablo Trinidad"/>
    </conversation>

Gráficos

El motor Nostalgic Works utiliza OpenGL ES para dibujar gráficos en pantalla, haciendo uso de la aceleración por hardware de los dispositivos móviles. Esto permite que el rendimiento general de los juegos sea mucho mayor y también la posibilidad de añadir efectos de post procesado, como el emborronamiento temporal de la pantalla (blur) o el ajuste de color, el cual me ha permitido crear ambientaciones diferentes usando las mismas imágenes. En el ejemplo del siguiente video, verás que durante el transcurso del juego, atardece y anochece gradualmente.

Uniéndolo todo

A continuación un ejemplo con parte de la funcionalidad implementada en el motor.


Documentación

Versión descargable en mi página de Linked in, pulsando en el icono al final de esta página.


Deja un comentario

Tu email no será publicado. Campos obligatorios marcados con *