GameJam UA – Resumen y balance

Este fin de semana pasado se celebró en la Universidad de Alicante la primera Game Jam. Una Game Jam es un evento que reune a desarrolladores amateur y no tan amateur con el objetivo de realizar un juego en 48 horas. Participamos formando un grupo de 2 programadores y una diseñadora, en total 3 personas. Comenzando el viernes a las 18:30, dimos rienda suelta a nuestras respectivas habilidades, y aunque el resultado no fue del todo satisfactorio, la experiencia ha servido para aprender y desarrollar más habilidad en el lenguaje de programación escogido: LUA. Sin más dilaciones, voy a hacer un resumen de lo que llevamos a cabo en esas 48 horas y luego un balance de lo que he aprendido participando en el evento y cosas que se mejorarán para la próxima edición. Test.

Tecnologías escogidas: LÖVE 2D y LUA

La tecnología escogida para desarrollar el juego fue el framework LÖVE 2D (https://love2d.org/), que usa un lenguaje de scripting llamado LUA (http://www.lua.org/); además hicimos uso de una librería en LUA llamada Zoetrope (https://bitbucket.org/klembot/zoetrope), que añade una capa de abstracción entre las funciones básicas de las que dispone el intérprete de LUA de LÖVE y el desarrollo del juego en sí. Este framework añade a LUA la posibilidad de programar con construcciones del lenguaje pseudo orientadas a objetos. Esto quiere decir que ciertas formas de diseñar propias de los lenguajes orientados a objetos se aplican, pero otras muchas no. Esto facilitó mucho la tarea a la hora de abstraer los elementos que formaron parte del juego, así como ayudar a desarrollar de manera más rápida y genérica las funcionalidades del juego. Zoetrope añade, además, múltiples herramientas y un muy útil sistema orientado a eventos, que implementa de manera más o menos adecuada el Observer pattern (http://en.wikipedia.org/wiki/Observer_pattern).

He de decir que era la primera vez que programaba en LUA en serio, y la experiencia ha sido muy grata. Es un lenguaje realmente potente, muy flexible y con una sintaxis fácil de aprender; por eso este lenguaje es el escogido en multitud de grandes proyectos de grandes empresas de la industria: World of Warcraft, Civilization V, Company Of Heroes, Crysis, y un largo etcétera. Además tiene una API de C bastante bien organizada, y el código fuente es intuitivo y fácil de seguir. El código fuente completo está disponible en http://www.lua.org/source/5.2/. Un muy buen recurso si estás interesado en el desarrollo de lenguajes de programación y compiladores.

Desarrollo del juego

Todo el código fuente escrito durante el fin de semana está disponible en el repositorio público de bitbucket:

https://bitbucket.org/albertofem/gamejam-ua

A pesar de que fue fácil hacerse con el lenguaje, y que más o menos ya dominaba el cómo se estructura un juego y qué tienes que tener en cuenta a la hora de desarrollarlo, surgieron varios problemas inesperados:

Rendimiento

Uno de los primeros fallos que pudimos notar fue el rendimiento de LÖVE 2D. El programar casi por completo la lógica del juego directamente en un lenguaje de scripting, además en un programa que no tiene hilos (no porque no LÖVE / LUA no los soporten, sino porque no dió tiempo a realizar un programar de estas características), causó que surgieran los típicos glitches relacionados con la velocidad a la que procesan todos los elementos en pantalla: colisiones que no llegaban a tiempo, pérdida de framerate, etc. Esto se arregló usando varios hacks, como por ejemplo corrigiendo aquellas colisiones que se notificaban tarde:

Diseño orientado a objetos

Como he comentado más arriba, Zoetrope contaba con ciertas facilidades para usar LUA como pseudo lenguaje orientado a objetos. Esto permitió desde el principio llevar a cabo un desarrollo separando cada elemento independiente del resto del sistema. Así pues, la mayor parte del código se desarrolló atendiendo al caso general, de modo que fuera reusable de manera global dentro del juego. Tenemos por ejemplo, la clase Enemy:

Esta permite definir distintos tipos de acciones genéricas comunes a todos los enemigos (en este caso que estén afectados por la gravedad), aparte de añadir cualquer otra acción específica de cada enemigo, dejando que el propio framework se encarge de actualizar, colisionar, etc. cada acción. Otras acciones que no dieron tiempo a implementar podrían ser: HitableEnemy, PathFindingEnemy, etc. Por ejemplo, dentro de la clase Player, que es similar, se implementaron acciones como JumpingActor, MovingActor, AttackingActor, etc.

Sin embargo, esto suposo un problema en el desarrollo a largo plazo, ya que ocupó demasiado tiempo del desarrollo, y al final no fue aprovechado todo el potencial que ofrecía. No obstante, estoy contento con el trabajo realizado, si bien en las últimas horas se fue un poco de madre y el código no fue escrito lo más elegantemente posible, pero bueno. Voy a dejar un tag de la versión original en Git, y en las próximas semanas iré dejando el código lo más decente posible, por si pudiera servir de ayuda en el futuro.

Problema de diseño

Otro problema, probablemente el más responsable de que el trabajo no saliera del todo satisfactorio, fue debido a la elección del tipo de juego a programar. Queríamos hacer un juego cargado de demasiados elementos, demasiados casos y comportamientos a tener en cuenta, y al final no pudimos llevar a cabo la mayoría de ellos. Esto hizo que el juego, cuya diversión estaba enfocada a contar con estos elementos, cuantos más mejor, en pantalla, resultara a la hora de la verdad no del todo divertido, eso sin contar los bugs a los que estaba expuesto por falta de tiempo en el desarrollo. Tampoco se tuvo tiempo para perfilar otros elementos importantes: control, música, puntuaciones, que suponga un reto, etc. Muchos participantes de la GameJam enfocaron sus juegos más al estilo minijuego, es decir, acciones repetitivas pero con mecánicas bien definidas y con buena respuesta. Es en este enfoque en donde se ve claramente la diferencia elemental entre lo entretenido que resulta un juego u otro.

Conclusiones y balance

Estoy muy contento con haber participado en esta GameJam. Me lo pasé realmente bien, y aprendí mucho sobre desarrollo de videojuegos, en especial LUA, eso por no hablar de la cantidad de gente genial y el buen rollo que se respiraba. Asistiré sin dudarlo a la próxima GameJam, esta vez intentando corregir la mayoría de errores cometidos, y porqué no, con más experiencia y conocimientos en este mundillo. Según los organizadores, la fecha aproximada será en Febrero de 2013, por lo qu antes tenemos, por ejemplo, la Ludum Dare en apenas 35 días, que puede servir para practicar y coger experiencia (http://www.ludumdare.com/compo/).

Os dejo con un vídeo en timelapse de todo el desarrollo (en programación). ¡Nos vemos en la próxima GameJam!

Diario de desarrollo (SeventhEngine): rendering pipeline

Una de las cosas más importantes, yo diría que la que más, en un motor gráfico es un rendering pipeline, algo así como “la tubería por donde pasan los gráficos”. Como si propio nombre indica, esta tubería es por donde pasará todo aquello que se muestre por pantalla, del primer al último pixel: texturas, tiles, animaciones, efectos, etc. Por eso es importantísimo organizar con eficiencia este aspecto. Puesto que este sistema tira directamente de OpenGL y SDL, en mi caso, he optado por organizarlo de la manera que paso a explicar en este post.

CRendering

Puesto que la manera más fácil de abstraer este concepto es el de convertirlo en un objeto, así lo he hecho. CRendering es la clase principal que controla todas las fases que recorre el motor desde que recibe una solicitud de mostrar un recurso por pantalla hasta mostrarlo y posteriormente limpiar sus recursos cuando ya no vayamos a usarlo. Está organizado, pues, de la siguiente manera:

  • Es requerido que aquello que vayamos a mostrar por pantalla esté previamente definidio en nuestro archivo de recursos (resources.xml). Como os podéis imaginar, CRendering tirará mucho de CResourceManager para obtener la información que necesita. No obstante, ambas abstracciones están los suficientemente separadas (es decir, está relacionados, pero no dependen el uno de otro en un sentido estricto; podríamos usar CRendering implementado otra manera de obtener los recursos o hacerlo internamente).
  • Cuando necesitamos mostrar uno de estos recursos por pantalla, tenemos que enviar una señal al gestor de recursos para que cargue del disco a la memoria dicho recursos, esto se hace en 2 pasos:
    • Llamamos a la función Load{Type}, que variará de un recurso a otro, por ejemplo: LoadTexture, LoadAnimation, etc. Como parámetro, unicamente necesitamos pasar el nombre del recurso que está definido en el XML.
    • Esta función a su vez llamará a CRendering para que cargue el recurso en memoria y le devuelva el ID asociado.
  • Una vez tenemos este ID, podemos llamar a las funciones de CRendering específicas para renderizar el recurso por pantalla.

Un ejemplo de implementación de estas interfaces se da en las entidades:

Como vemos, cuando en la entidad queremos cambiar que tipo de gráfico tenemos asociado a la entidad, primero cargamos el recurso, e indicamos que tipo de recursos está haciendo uso la entidad. Cuando el game loop llame al método UpdateGameLogic(), dependiendo de que tipo de recurso disponemos, llamará a una función u otra de CRendering. Por ahora tengo implementadas para el caso de ENTITY_ASSET_TEXTURE y ENTITY_ASSET_TILE, pero implementar animaciones y otros tipos de recursos se hacen de manera similar. Además, siendo este el modelo base de entidades, en las entidades creadas por el usuario, todo esto se gestiona de forma transparente, por lo que el usuario sólo tiene que usar la función correspondiente a qué recurso quiere usar (en este caso SetTexture() y SetTile()). Las ventajas de este sistema es que separamos completamente la implementación a nivel de gráficos de CRendering del resto del sistema; así pues, sólo necesitaremos pasar aquellos elementos dinámicos que cambian durante el uso de un gráfico: qué gráfico en sí (ID) y la posición donde vamos a dibujar. Este diseño además permite que en el futuro se pueda integrar el control de cámaras, escala, resoluciones, etc. también de manera interna y transparente.

Subsistemas de CRendering

Como es obvio, CRendering a su vez necesita estar divida en subsistemas, dependiendo de que tipo de gráfico queremos mostrar, actuará un subsistema u otro. Para este motor gráfico he elegido 3 subsistemas: CTexture, CTile y CAnimation. Con estos 3 tipos de gráficos podemos dibujar cualquier cosa imaginable. De hecho, puesto que CTile no es más que una especialización de CTexture, podríamos decir que sólo tenemos 2 tipos de unidades gráficas para mostrar: texturas y animaciones. El caso de las animaciones requiere un comentario por separado, puesto que por su naturaleza, está formada por varias texturas cuya representación varían a lo largo del tiempo. Hablaremos más adelante sobre esto.

Así pues, el módelo básico de CRendering queda resumido en la siguiente imagen:

Untitled

Tilesets y CTile

Como he comentado antes, los tiles, es decir, trozos de una imagen que reune múltiples, es un caso especial de las texturas. Es por eso que en los recursos están definidos por un lado los tilesets, la imagen en sí, y cada uno de los tiles de los que dispone. Pudiendo extraer de un tileset el tile que necesitamos podemos juntar los gráficos de nuestro juego en un tileset determinado y sacar los gráficos de ahí. De hecho, se podría agrupar en un mismo tileset todos los gráficos del juego y el sistema seguiría funcionando. En general, para cuando queremos cargar un tile, hacemos lo siguiente:

  • Comprobamos que tanto el tileset como el tile existe en nuestro archivos de recursos.
  • Cargamos en primer lugar el archivo del tileset en memoria.
  • Acto seguido extraemos la porción que necesitemos y la almacenamos como textura de OpenGL

Esto tiene 2 ventajas inmediatas: sólo necesitamos cargar 1 vez en memoria el tileset completo; el resto de tiles que extraeremos de él lo harán sobre el tileset ya cargado en memoria, con lo cual es eficiente. Sin embargo ocurre que según con que implementación de OpenGL estemos funcionando, hay definido un tamaño máximo de texturas en GL_MAX_TEXTURE_SIZE, además de que es conveniente almacenar texturas con tamaños de potencias de 2. La segunda ventaja es que tratamos con las porciones como si fueran texturas completas de OpenGL. Esto permite una flexbilidad extraordinaria a varios niveles, y no es difícil imaginar lo sencilla que sería, por ejemplo, aplicar scaling o transformaciones globales.

Un ejemplo de tileset:

dungeons

Como se puede ver, contiene gráficos mínimos para muchos tipos de mazmorras del juego (The Legend of Zelda: A Link To The Past). El fondo en verde es porque antigüamente no existían formatos como el PNG (que llevan canales alpha) y había que usar un color (como en las películas, el verde fosforito) para tratarlo como transparente.

 

La semana que viene intentaré actualizar para seguir comentando progresos. Tengo que admitir que el progreso del proyecto conforme al plan original se ha retrasado bastante, pero seguiremos dándole caña para ponerlo al día. En 3 semanas tengo exámenes de la UNED, no obstante… ¡intentaré actualizar!

Diario de desarrollo (SeventhEngine): inspiraciones y motores open source

Una parte bien importante de llevar a cabo los proyectos que nos proponemos, es 1) fijarse en lo que han hecho los demás y coger ideas para lo tuyo y 2) tener fuentes de inspiración contínuas que nos animen en el duro trabajo del día a día. La mayoría de gente cuando se propone hacer algo, lo suele dejar a los pocos días, porque la emoción del principio se disipa rápidamente, no es duradera. Cuando se ha ido ese “subidón” inicial, lo único que queda es trabajo duro y esfuerzo, y la mayoría de gente no está dispuesta a pasar por ello. En términos de darwinismo social es algo bueno, porque hace destacar a los que valen de los que no. Por eso es muy importante mantenerse en la línea y motivarse durante todo el proceso, de manera casi sistemática: lecturas, fijarse en los casos de otras personas de éxito, etc. En mi caso, me ayuda mucho recordar porqué estoy metido en esto y le dedico tantas horas y esfuerzo: la pasión por los videojuegos.

El mejor juego de la historia

Uno de mis juegos favoritos, que no sorprendará a nadie, es Shadow of the Colossus. Aun a pesar de ser un conocedor tardío de este trabajo (en el remake de PS3), enseguida capté algo de especial en este juego. Más que un videojuego, es una obra de arte completa; una experiencia sensorial que eleva, si se puede decir, a aquellos que saben apreciarla en su justa medida. Todo es especial en este juego, desde el diseño del mundo austero, el sencillo guión pero de transcendencias filosóficas, el esoterismo y epicidad que desprenden las batallas, y la música, la maravillosa música. Con este breve resumen quiero llegar a lo importante de este meollo. Y es el porqué la carrera del desarrollo de videojuegos es especial: es en dónde dos disciplinas tan distintas como el arte y la ciencia se juntan, y aun a pesar de que soy consciente de que programación / diseño del videojuego no son la misma la cosa, es este el punto de inflexión donde reside la importancia del trabajo que nosotros (los programadores) hacemos; el imprimir pasión en lo que hacemos, en cada línea de código, el construir y hacer posible un mundo artístico de carácter transcendente, es simplemente espectacular. Por eso estoy convencido de que esta profesión sólo se sirve si tienes pasión por ella.

shadow-of-the-colossus-galloping-by 
Shadow of the Colossus es pura inspiración

Motores Open Source

Otra parte esencial de llevar adelante los proyectos que nos propones, es el fijarse en cómo lo han hecho otros anteriormente a nosotros. De nada sirve reinventar la ruedad, y en el desarrollo de software esto debería ser un máxima a cumplir siempre que podamos. Obviando el hecho de que nos puede interesar implementar / programar según que partes como ejercicio de aprendizaje, siempre deberíamos tener en cuenta y revisar a menudo código de otras personas que han resuelto los mismos problemas que nosotros. Quién sabe, igual se nos ilumine la bombilla y podamos idear otra manera mejor de resolver un problema o implementar un determinado diseño que a su vez pueda servir a futuros programadores.

Motores gráficos libres hay muchos, pero voy a destacar y comentar 2 de ellos, que son los que estoy revisando a menudo, ya que son 2 motores de una calidad bastante elevada y usados en juegos / plataformas modernas. Si bien los 2 se usan en gráficos en 3D, hay muchas partes que son compartidas por el objetivo de mi proyecto, además de que casi todos los motores en 3D llevan algún tipo de gestión de gráficos en 2D. Empezamos:

idTech 4

A todos nos sonará el nombre de John Carmack (si no es así, abandona el blog por donde lo entraste); este programador mítico es senior developer y co-founder de id Software y ha participado en el desarrollo de todos los motores de tecnología punta que han visto la luz en forma de videojuegos espectaculares. El que comento hoy es el id Tech 4, el motor gráfico de Doom 3, y que recientemente ha pasado a ser software libre bajo una licencia GPLv3. La URL del proyecto en GitHub es la siguiente: https://github.com/TTimo/doom3.gpl

La primera cosa que me sorprendió mucho fue lo distinto en estructura que se muestra este motor. No es tan orientado a objetos como otros motores; sigue conservando un estilo estructural clásico de cuando sólo existía C, y aunque usa las bondades de las clases, templates y demás, su estilo sigue siendo más C que C++; es un uso bastante elegante de ambos estilos predominantes de estos lenguajes de programación.

469881_20040805_screen004
Doom 3, el juego que pondría al id Tech 4 en lo más puntero en motores gráficos de su época

Por otro lado, otra cosa que me ayudará bastante en el futuro es la manera en la que organizan la estructura del motor para que sea multiplataforma. Hay muchas optimizaciones que llevar a cabo, y en el código hay muchísimos ejemplos: implementación de threads, game loops, eventos, etc. Por ejemplo, echando un vistazo a la implementación del loop principal, vemos la cantidad de cosas que hace falta para Windows, y lo sencillo que es hacerlo en Linux. Eso nos puede dar una idea de cómo enfocar la gestión de los recursos de nuestro programa, la organización de carga de los subsistemas, especialización para un determinado sistema operativo / arquitectura, etc.

HPL1 y Penumbra Overture

Otro caso de estudio interesante es el del trabajo de Frictional Games (creadores de Amnesia), y que hace un par de años liberaron el motor gráfico de su primer trabajo, Penumbra, también bajo licencia GPL. Este motor, en el que se nota una influencia más profunda del estilo orientado a objetos, tiene la peculiaridad de que también está disponible un juego completamente funcional (Penumbra Overture) que hace uso del motor, lo cual lo hace ideal para coger ideas a la hora de diseñar e implementar múltiples áreas, como las interfaces de usuario. Además, también está disponible el código fuente de las múltiples herramientas que todo game engine debe llevar en el pack, como editor de mapas o gestor de recursos (en el caso de un motor en 3D habría que añadir editor de partículas, modelos, visor de escenas, y un largo etcétera).

HPL es menos elitista que otros y usa extensivamente el STL (vector, map, multimap, set, etc.), y nos puede servir para darnos ideas de como organizar nuestras estructuras de datos entorno a estos contenedores y como implementarlas de forma eficiente. Sin embargo, uno de sus inconvenientes es que apenas se encuentra comentado, y eso nos puede resultar un impedimento a la hora de estudiar a fondo el código, además de tener una estructura de ficheros bastante grande y cuesta ver a priori para qué sirve para cosa y como se relaciona con el resto. Para esto es mejor bajarse el proyecto de Visual Studio y compilarlo por tí mismo. Si necesitas estudiar en concreto como hace tal o cual cosa, puedes recurrir a herramientas debugging típicas, como los breakpoints.

screen22
HPL1, el ejemplo perfecto de que no hacen falta millones de dólares para alcanzar una gran calidad

Las URLs en GitHub de ambos proyectos son: https://github.com/FrictionalGames/HPL1Engine y https://github.com/FrictionalGames/PenumbraOverture/.

Monocle Engine

Otro motor gráfico open source, pero un más humilde, es el Monocle Engine. Es un motor únicamente 2D, y está en continuo desarrollo; es lo más parecido que he encontrado a cómo quiero que sea siendo mi proyecto al final. Tienen el código fuente comentado y como siempre en GitHub: https://github.com/zaphire/Monocle-Engine/. Como véis, fijarse en el código de los demás es una tarea harto importante que no debería ser pasada por alto en ningún caso. Los fundamentos de la mente creativa del ser humano se apoyan siempre en lo que personas como nosotros han hecho antes que nosotros, y la programación no es una excepción.

Proyecto de año nuevo: mod de Amnesia

El otro día en casa de un amigo se me ocurrió la idea de hacer un mod para Amnesia. Ya sabéis, el mejor juego de terror de este año pasado, y probablemente uno de los mejores de la historia. El caso es que los chicos de Frictional Games (al contrario que muchas compañías mainstream) ponen a disposición de cualquier sus herramientas de modding, que sirven para currarse cualquier tipo de historia que te quieras imaginar usando el motor gráfico de Amensia (HPL2). La idea base de este proyecto es hacer un mod jugable, que no lleve demasiado tiempo, y que sea corto y original. Un tiempo de duración aproximado sería del orden de 30min – 1 hora. Además, será algo distinto a Amnesia (que gran parte del juego consiste en explorar y resolver puzzles), y darle un toque más de Survival Horror. Además, será un punto de partida interesante para el aprendizaje de creación de videojuegos, a todos los niveles, mapeado, scripting, diseño de personajes, y un largo etcétera.

mapviewer
Así es como luce una de las herramientas de modding, en este caso el MapViewer

Me acompaña en esta gloriosa empresa Krieg_Korp (http://zombiedilema.blogspot.com/) que será el encargado de inventarse una historia bestial para el mod, el diseño de la jugabilidad, niveles, etc. Recomiendo echar un vistazo a algunos de sus escritos en su DeviantArt , os gustarán(http://mobiusklein.deviantart.com/gallery/). Es posible que el juego vaya acompañado de alguna historia breve para aumentar la inmersión del mismo; por otro lado, puesto que no tenemos artista gráfico, usaremos la base de materiales/entidades/texturas/sonidos que lleva por defecto Amnesia. Ni que decir tiene que el mod será gratuito, y todo el código fuente estará bajo licencia GPLv3. En próximas entradas pondré a disposición el repositorio de GitHub.

Poco más que decir por ahora. Usaré el blog como medio de propagando del mod y para llevar un diario de desarrollo. En él pondré un seguimiento de cerca de todo el proceso, desde el aprendizaje de las herramientas del HPL2, programación del scripting del juego, decisiones en cuanto a jugabilidad, niveles, etc. Si tenéis alguna sugerencia podéis usar los comentarios :) . ¡Ah¡, y estará en español, pero si tiene éxito ¡no descarto traducirlo al inglés!

¡A trabajar!

Post Navigation