sábado, 26 de marzo de 2011

Recocido de Profanation sobre cama afrutada de XNA y con relleno de MonoGame (o XNATouch)

Contaba en la entrada de ayer que tenía ganas de hacer un juego para el iPhone y que había estado buscando durante días algo con lo que desarrollarlo resultara bueno, bonito fácil y barato. También contaba que, finalmente y descartando los entornos integrados, había decidido hacer sendas pruebas de concepto con cuatro de las chopocientas mil alternativas basadas en los lenguajes que a día de hoy exiten para desarrollar para este dispositivo. Y que de las cuatro había decidido empezar con la que, sospechaba, me resultaría más fácil dado que con el lenguaje de programación C# es con el que más años de experiencia tengo y a estas alturas conozco bastantes truquillos de su sintaxis y buena parte de sus interioridades, amén de que me resultaría más comprensible el código que viese en los ejemplos sin tener que andar intentando averiguar para qué servían esos corchetes, a qué venían esos puntos y coma o por qué se metía ese bloque de código indentado en este sitio y no en uno más arriba. «¿¡Pero de dónde narices ha salido esta variable!?»

Las dificultades de hacer un (buen) juego y el objeto de la prueba de concepto.

Si me pidiesen a mí, absoluto lego en la materia, que hiciese una lista ordenada, de mayor a menor dificultad, con los elementos más difíciles para conseguir un buen juego, diría que en primer lugar estaría, sin lugar a dudas, lo que vendría a ser a modo abstracto el diseño, que incluiría cosas como el concepto, los elementos de jugabilidad, etc., etc. Lo pongo el primero porque una cosa es tener una idea como, por ejemplo, «voy a hacer un juego en el que el jugador tenga que mover unos bloques por un nivel para poder salir de él» y otra muy distinta hacerlo. Lo que vulgarmente se conoce en el refranero popular como «del dicho al hecho hay un gran trecho». Vale, lo del laberinto es fácil y la idea pinta bien, no lo voy a discutir. Ahora diseña veinte o treinta niveles, con el adecuado incremento de dificultad de uno a otro, para que el jugador no lo termine en cinco minutos, pero que además no sea tan difícil como para abandonarlo frustrado. Si alguno no me cree que se ponga a diseñar laberintos en donde el jugador tenga que ir pasando por una serie de puntos para activar puertas secretas y tal y tal y que, en resumen, resulte interesante.

Después de las tareas de diseño estaría la parte gráfica. Hay gente que dibuja muy bien y esto lo tienen ganado. Para mí no y es algo con lo que tengo que lidiar si finalmente quiero hacer algo que resulte interesante. En mi caso es un elemento limitante y no descarto que, llegado el caso, acuda a un freelance para encargarle los gráficos. Es asombrosa la cantidad de sitios en Internet que son infraestructuras de proyectos para contratar freelancers y hacer seguimiento del trabajo. Pero hete aquí que el Inglés se vuelve nuevamente imprescindible. En cualquier caso, en este punto quería evitar enfangarme con esto.

Ya en tercer lugar, y sin desmerecer otros muchos aspectos también complicados como por ejemplo el sonido, para mí estaría la programación en sí y, dado que esta es la que en primera instancia me preocupa a la hora de tomar una decisión, es sobre este término que planteé la prueba de concepto. Por ello, para poder concentrame en el código, tenía que salvar de alguna forma los dos apartados anteriores. Y no se me ocurrió mejor forma que hacer un remake de algo ya existente. Esto me quitaría el problema de los gráficos (copiar con un poco de trabajo los originales, si fuera menester) y del diseño del propio juego (copiar el original sí o sí). No se trataba de hacer el juego entero, ni siquiera toda su funcionalidad; simplemente buscaba concentrarme en cómo se podía hacer «aquello de entonces con esto de ahora» y llevar a la práctica dos o tres de las características del original. Además de que se podría incurrir en violación de derechos de propiedad.

Abu Simbel Profanation

Supongo que todos los que crecimos adorando un ordenador y siendo pioneros en esto del ocio electrónico basado en ordenadores personales, tendremos nuestros juegos favoritos. Esos que cuando en alguna conversación de cuarentones nostálgicos se empiezan a enumerar, revivimos con especial entusiasmo. Yo tengo muchos, en particular los de Ultimate Play the Game [@ Wikipedia] y los de Dinamic Software [@ Wikipedia], de mi época de Spectrum (de 12 a 15 años). Pero si hay uno en particular que encabeza la lista es el de Abu Simbel Profanation. Para mí este dificilísimo juego de 1985 (yo tenía 13 años), del que creo que no llegué a pasar de la pantalla dieciséis, supuso una revolución en los juegos de Spectrum en el género de plataformas y se trata de uno de los dos o tres que siempre quise versionar para otras plataformas. Cuando empecé a hacer mis pinitos con el código máquina (lenguaje ensamblador) para el Commodore, intenté implementar la impresión del mapeado de pantallas con superbloques [1]. Creo que durante una semana gané todos los premios al ratio de cuelgues de ordenador por hora causados por saltos condicionales fuera de código y por accesos a memoria fuera de rango. Vamos, que desistí frustrado.

Con esta prueba de concepto parecía que esta iba a ser la oportunidad de, si no todo, por lo menos programar las primeras pantallas de este genial juego. Tocaba «desempolvar» el emulador de Spectrum [Viejos tiempos para el jugador casual] y empezar a capturar las pantallas. Elegí Profanation para hacer la prueba de concepto del código con XNA. Ya tenía diseño y gráficos resueltos. Tan sólo había que recortar cada frame de la animación y ya estaba. En teoría.

Los gráficos, las escalas y primeros tropiezos

Aunque no viene mucho al caso, decir que es asombroso que cuando uno los necesita no funcionan. Justo un par de días antes de ponerme con la modernización actualicé tanto GIMP como Inkscape en mi equipo y dejaron de funcionar. Cada cierto tiempo lanzo el (ahora temido) comando de actualización de MacPorts. Sin saberlo, con la última descarga masiva de actualizaciones había conseguido dejar inservibles tanto uno como otro. Vaya mala suerte. Así que harto de andar para delante y para atrás intentando resolverlo abrí la App Store de MacOS X, busqué y me pillé dos de diseño vectorial y PixeImator. 60 euros más pobre pero me quité del golpe los problemas. De los primeros no estoy muy contento, pero el segundo es una gozada. El software en realidad es muy barato —me apunto que un día tengo que escribir sobre esto— y no me arrepiento del dinero gastado. La integración de GIMP en Mac era inexistente (se requiere X11), algo que le restaba feeling al usarlo. Vamos, me olvidé de él en diez minutos de usar el nuevo. Visto retrospectivamente está claro que no era amor lo que sentía por él.

Tras este inciso me puse a pensar en cómo sería el diseño en el iPhone, que tiene una pantalla de 320 x 480 y en el iPhone 4, en el mismo área, una resolución de 640 x 960, mientras que el juego original tenía 256 x 192. Además que había que meter botones en la pantalla para manejar al machango. Aquí me encontré que los puntos por pulgada de las pantallas de ordenador tienen una densidad bastante menor que la pantalla del terminal y que esto podía conducir a errores en las escalas. Después de hacer un boceto del diseño de la pantalla y exportarlo a la resolución del iPhone, basta con reajustar la densidad de puntos. El cálculo es tan sencillo como aplicar una relación de proporciones o una regla de tres donde comparamos el alto de la pantalla del iPhone con su densidad de puntos (163 ppp) a cómo debería verse en una pantalla normal (96 ppp) o la del portátil (112 ppp) [2]. Vamos, Altura = 320 x 96 / 163, lo que da unos 188 píxeles de alto. Reescalar la imagen y comprobar si el botón ha quedado de un tamaño adecuado para pulsar con el dedo gordo —yo lo tengo muy gordo— poniéndolo directamente sobre nuestra pantalla y si los gráficos originales quedan mínimamente distinguibles. Así es como queda el resultado a la escala de la pantalla del iPhone, dependiendo de la densidad de puntos de tu propio monitor, claro:


Hombre, yo no sé ustedes, pero si bien los botones quedan a un tamaño más o menos prudencial en la pantalla, el protagonista resulta prácticamente indistinguible. Iba a tocar reescalar todo y buscar la forma de que todo encajase en pantalla. En última instancia se trataba de una prueba de concepto y tampoco tenían que ser las mismas pantallas. Bastaba con que el personaje se pudiese mover por algunas plataformas y saltase, controlar las colisiones con algún enemigo tonto y poco más. Vamos, hacer un mix de Abu Simbel Profanation y Mario Bros. Visto lo cual, me puse a rehacer los gráficos. Tuve una especie de deja-vu porque esto mismo hice, de forma algo más cutre, en octavo de EGB pasando los sprites a hojas de cuadraditos para calcular los códigos binarios de cada uno de los bytes que componían el gráfico de 16x16 bits, pero ahora capturando pantalla y reescalando el bicho a 32x32. Vamos, un curro. Y se suponía que la intención era no perder tiempo con esto.

Entonces pensé que tal vez no tendría que hacerlo. Hace años tuve la oportunidad de jugar a un remake que tropecé por casualidad en la zona de ramakes de Computer Emuzone, en la de Remakes Zone o en alguna similar. Estaba hecho en Java y la verdad que era algo simplón en gráficos, pero resultón. Para mí más que suficiente. Busqué y enseguida lo encontré. Y no sólo ese. El autor ha hecho otra versión bastante mejor y que, además, también está para Mac. Aún mejor, se puede descargar el código fuente desde su página Web. Pero aún queda lo mejor de lo mejor: ¡¡¡Viene con los gráficos!!!

Si son nostálgicos de los juegos de 8 bits, en la página de M.A. Software podrán encontrar algunas cosas muy interesantes. Este hombre es un crac.

A base de rapiñar los gráficos de Miguel Ángel, ya tenía resuelto el segundo asunto en orden de complejidad. Aunque bueno, todo todo no lo he rapiñado. También quise aportar mi granito de arena en el apartado gráfico y añadí la secuencia de una muerte bastante truculenta.


Tocaba ponerse a aprender XNA.

¡Ya sé XNA! Al menos los cuatro conceptos básicos

En Internet hay muchísima documentación sobre XNA, suficiente para aprender, pero yo me fui directo a la bibliografía. En mi caso recurrí a un libro que me ha parecido muy entretenido y bien escrito: 'Beginning XNA 3.0 Game Programming' [3]. Tras una lectura rapidísima de los capítulos dedicados a la programación en 2D (de momento no me interesa la parte en 3D), puedo concluir que XNA es muy sencillo de aprender y que tiene cuatro conceptos básicos que comprender: la clase SpriteBatch, heredar de GameComponent —mejor aún de DrawableGameComponent— y los métodos Update ( GameTime gameTime ) y Draw ( GameTime gameTime ). Con estas tres ideas, y cargando las imágenes en clases Texture2D uno ya se puede meter a hacer algo que resulte interesante.

Aunque sea por el placer de escribir tres líneas de código, recomiendo a todo el que tenga curiosidad que intente mover un sprite por la pantalla. De ahí a conseguir un hit en Xbox 360 no hay nada. Y confieso que me ha sorprendido la facilidad con que se aprenden los antes mencionados conceptos básicos y lo fácil que es leer el código C# que hay de ejemplo por todas partes.

Yo tardé un día en leerme los cuatro primeros capítulos, los dedicados al 2D, y sentarme a escribir código con más o menos seguridad sobre lo que estaba haciendo.

Manos a la obra. ¡Qué divertido!

Como usuario de Mac, y sin querer recurrir para este caso a la máquina virtual que siempre tengo con Windows, mi intención era hacerlo todo con software que se ejecutase de forma nativa en mi máquina. Para ello basta con descargar Xcode con el SDK de iPhone [4], instalarse la última versión de Mono para Mac, hacerse con la versión demo de MonoTouch, instalar MonoDevelop y bajarse la última versión de MonoGame, antes conocido como XNATouch. En mi caso me lancé directamente a usar la versión del repositorio, la 1.6, ya que en ésta los espacios de nombre son los mismos que los del XNA original: Microsoft.XNA.Framework.

Repito que tras la experiencia con el apartado gráfico, la idea final era hacer una especie de Mario Bros usando los gráficos del remake Abu Simbel Profanation Deluxe. Pero al resultar tan relativamente sencillo hacer algo con XNA, te acabas enganchando y te dices, «bueno, voy a meterle ahora esto», y así una tras otra. Vamos, que lo que inicialmente había pensado me llevaría tres días, lo acabé convirtiendo en seis o siete días en los que me lo he pasado muy bien haciendo que el machango fuese de un sitio para otro. En dos días ya tenía bastantes cosas hechas, pero lo siguiente era meter sonidos, hacer un scroll de pantalla, meter distintos enemigos con animaciones diferentes, que el muñeco mirase en las diferentes direcciones como hacía el original, etcétera, etcétera.


Pero no era totalmente gratuito este sobre esfuerzo. MonoGame es un producto bastante verde, según lo que se lee en diferentes sitios. Confieso que tenía la creencia de que la cosa haría aguas por todos lados y que la mitad de lo que hiciera no funcionarían. Pero no. Cosa tras cosa que iba metiendo el juego seguía funcionando. Y muy bien, todo sea dicho. Sobre todo porque el código espagueti con el que lo hice dudo que sea el mejor para probar el rendimiento del juego. Si no hice más cosas es porque, precisamente, como no esperaba hacer mucho, la mayoría de las primeras cosas las hice en plan hard coded, como las cuatro pantallas que al final reproduje del juego original. Hay que ver la cantidad de horas que me he metido calculando las coordenadas de cada uno de los bloques que había que pintar en la pantalla.

Por cierto, en la captura aparecen unas áreas rectangulares de colores. Esto se debe a que, ya puestos a meter cosas, también podía superponer las áreas de colisiones para comprobar si todo funcionaba como debía cuando uno se aproxima a un enemigo.

Un pequeño apunte sobre música

Ya como último paso antes de dar por cerrada la prueba de concepto, se me ocurrió meter algo de banda sonora al juego. Los efectos de sonido también se los rapiñé a Abu Simbel Profanation Deluxe, pero me apetecía probar a meter una música de fondo mientras jugaba. Se me ocurrió recurrir a RKO, donde hay cientos de versionados de temas musicales de los juegos del Commodore. Hay algunos muy buenos. Ni corto ni perezoso escuché unos cuantos de los últimos que se habían publicado y me decanté por el tema 'Cauldron II (The Witch Who Stepped in Dub)', de Sound of Hazel (http://www.soundofhazel.com). Le da marchilla a la prueba de concepto. Y, lo mejor, es bastante sencillo dejarla sonando. Tanto como crear una instancia de efecto de sonido e indicarle que se reproduzca en bucle. Pongo algo de código.

public static void PlayMusica ()
{
   musicaInstance = musicaJuego.CreateInstance ();
   musicaInstance.Volume = 0.2f;
   musicaInstance.IsLooped = true;
   musicaInstance.Play ();
}

Reproducir el resto de efectos de sonido es exactamente igual de fácil.

El resultado

Está extendida la creencia de que una imagen vale más que mil palabras. Y que un vídeo más que mil imágenes. Pues por no llevar mucho la contraria, aquí va un pequeño vídeo sobre cómo ha quedado finalmente la prueba de concepto. La chicha tarda un poco en empezar, sean pacientes.



Pero… el simulador no es el dispositivo

Confieso que he quedado gratamente sorprendido por el trabajo de la gente de MonoGame. Me preocupaba el hecho de no conocer nada de XNA y tener que aprender con un producto que, tal vez, fallase más de la cuenta. De hecho, cuando uno descarga el código desde el repositorio del proyecto, la mayoría de las demos que lo acompañan no funcionan. Pese a ello, el proyecto empezándolo desde cero y aplicando las pautas aprendidas en el libro mencionado antes ha funcionado en todo momento.

Sin embargo hay algo que me sigue preocupando. En las pruebas con el simulador, todo funciona perfectamente. Rara vez los frames por segundo bajan de 58, sabiendo que el hardware gráfico del iPhone sólo alcanza los 60 fps. Pero el simulador no es el dispositivo, y algo que funciona perfectamente en el simulador puede ir fatal en el hardware final. Esto supone un riesgo enorme a la hora de adoptar esta tecnología. Pueden significar muchas horas de trabajo tiradas a la basura y/o 400 euros mal invertidos [5] si resulta que desde el principio descubrimos que la cosa no tira. Pero ya se sabe, quien no arriesga no gana. Y tal vez sea mejor perder ese dinero que echar 100 horas en algo que luego no va a funcionar y que seguimos con la incertidumbre hasta que decidamos gastarnos la pasta.

Siguiente paso

Mientras decido si invertir el dinero o no en MonoTouch, ya voy pensando en qué haré a continuación. En la lista el siguiente es Cocos2D. Aunque en teoría lo ideal sería repetir lo mismo que he hecho con MonoGame, la realidad es que no se me apetece —y no voy a repetir de nuevo— lo que he hecho. Supongo que tiraré por algún otro clásico del que haya también gráficos disponibles que poder buitrear. Aunque esta vez espero no dedicar tanto tiempo a pulir pijadas y llenar la prueba con detalles que a la postre son insignificantes en el valor de conjunto. Ya veré. Lo único que sé es que en las últimas dos semanas me lo he pasado genial haciendo esta prueba de concepto.



[1] Si mi memoria no me engaña, y no empiezo a inventarme ya las cosas, leí por primera vez esta idea del «superbloque» en un artículo sobre programación de videojuegos que se publicó en MicroHobby o en MicroManía. Aunque a estas alturas ni estoy seguro de que fuera ese el término ni de que fuera en una de esas revistas. El superbloque vendría a ser lo que hoy se denomina en todas partes como tile (mosaico).
[2] En http://members.ping.de/~sven/dpi.html hay una calculadora que te dice los dpi de tu pantalla en función de la resolución.
[3] Actualmente la versión 4 de XNA deja como obsoletas algunas de las cosas que estaban disponibles en la versión 3. Sin embargo, tanto el proyecto MonoGame como la alternativa ExEn, actualmente en desarrollo privado, no soportan completamente la última versión de XNA.
[4] Para poder probar el código realizado con MonoTouch hay que contar con el simulador que ofrece Apple con el SDK. Para ello es necesario darse de alta en el programa de desarrolladores de Apple (que es gratis) y ya se podrá descargar. Alternativamente, y desde hace poco, también se puede conseguir directamente en la App Store pagando 4€.
[5] En realidad algo menos teniendo en cuenta que sea cual sea la opción que finalmente se elija para hacer un juego (o cualquier otra aplicación de iPhone) será necesario contar con la licencia de programador iOS, que al cambio viene costando unos 80€.

No hay comentarios: