martes, 30 de abril de 2013

Programando para Android - 3. El mapa

El colega kpacha me hace una pregunta muy interesante en el capítulo anterior y merece un mínimo análisis.
Me dice que eso de guardar el mapa en un archivo de imagen podría ocupar demasiado espacio comparado con almacenarlo en un archivo de texto plano, que tiene un byte por casilla y encima se puede comprimir.

Puede ser, porque el archivo de mapa de bits probablemente deberá tener al menos 3 bytes por cada píxel, uno para cada componente de color (RGB) otra para el canal alfa y vete a saber qué más y no podríamos aprovechar la compresión jpg porque necesitamos píxels "perfectos". Aunque sí podríamos usar compresiones tipo zip.

Para empezar aviso que en realidad la gracia de hacer el mapa con una imagen no es el espacio, es que se pueden "dibujar" las plataformas muy cómodamente con cualquier editor de imagen. Yo las he hecho con el Gimp y es escandalósamente rápido con la herramienta lápiz.

Pero sí es verdad que si se tratase de un juego con muchísimos mapas o que fuesen muy grandes podría empezar a notarse el espacio ahorrado. Así que he hecho uno de los mapas en txt a ver qué pasa.


Son 28 columnas y 15 filas. Aquí podéis ver los archivos que he hecho para comprobar el tamaño:


El excel lo he hecho para crear más rápido el de texto, pero está claro que no sale a cuenta, ocupa mucho más incluso comprimido. En formato csv comprimido mejora pero no alcanza a los otros.

El tamaño 1KB que marca es inexacto, hay que ir a propiedades de cada archivo o bien abrir nuestra querida consola de comandos:


Donde podemos ver que la cosa está más reñida de lo que parece.
map3.png es el archivo original que uso en el progama. Son 240 bytes sin hacer nada especial. No está nada mal y es mejor que el mapa.txt (450B) sin comprimir y mejor que el csv comprimido.
Entonces vemos que el mapatxt.zip es bastante mejor y que nos ahorra una buena proporción de espacio. Sería el momento de comprimir el png pero vemos que map3png.zip... ¡Ocupa más que sin comprimir! Lo cual nos da la idea de que el formato png lleva incorporadas compresiones lossless bastante buenas.
Entonces parece que ocupa menos el txt comprimido... pero hay algunas opciones en el formato png para ahorrar información en la cabecera del archivo. Si al guardar desactivamos todas estas opciones ganamos muchos bytes:


Así el archivo de 28x15 = 420 píxels se queda en 145 Bytes. Que ya está muy bien. Seguro que podríamos inventar algún formato para mejorar esos números, supongo que aún estamos lejos de la entropía mínima. Pero también habría que programar toda la lectura y análisis del archivo mientras que ahora es una única línea.

Incluso hay una opción para minimizar aún más el png, que sería usar color indexado. Si indicamos que solo va a haber un máximo de 8 colores se reduce la cantidad de bits por píxel y se consigue que ocupe 130B.

Además este minimapa tipo png se puede usar directamente dentro del juego para diferentes cosas como un "mapa en pantalla" superpuesto para que el jugador se ubique. También como previsualización en una hipotética pantalla de selección de niveles. Pero sobre todo pintar las plataformas con el ratón me ha convencido desde el principio.

Más cosas, he retocado el control de juego para hacerlo más estándar y he dibujado los controles en pantalla y las monedas. También he cambiado imágenes y el recorrido, los parámetros físicos del personajes y otros detalles...


jueves, 25 de abril de 2013

Programando para Android - 2. En marcha

Ya tengo un primer prototipo muy esquemático con el funcionamiento básico.
Está organizado en dos pantallas usando las Screens del libgdx, una de bienvenida y después la del juego en sí. En punto de entrada carga la MainScreen que a su vez carga la GameScreen cuando se toca la pantalla.

En la GameScreen se carga un escenario de una manera que he visto por ahí y me ha parecido muy curiosa y muy útil. Se prepara previamente una imagen de mapa de puntos así:

Y luego el programa lee la imagen y según el color de cada píxel crea cada elemento en el lugar adecuado. Pero no crea el gráfico, solo el objeto. Todo queda flotando en el mundo de las ideas de Platón. Es lo que sería el Modelo en una arquitectura tipo MVC (Modelo-Vista-Controlador). Todas las operaciones, movimientos, interacción, lógica... se calcula en el modelo. Una vez esté preparado hay que renderizarlo, que es la función de la Vista, coger los elementos y representarlos en la pantalla. La idea sería esta:

El controlador en cambio lo he mezclado con el modelo así que es probable que tenga que reorganizar cosas. Aunque tampoco hay tanto que "controlar", no es tan grave.

La Vista (archivo WorldRenderer.java) se encarga de preparar la ventana de la aplicación, apuntar la cámara a la zona que nos interese, poner una imagen de fondo (está desactivado de momento) y representar cada elemento del juego con su imagen correspondiente en la posición adecuada. Aquí pongo un ejemplo en que se recorre toda la lista de bloques (paredes y suelo) y se dibuja una imagen en cada posición:

for(Block bl: world.blocks){
              batch.draw(blockImage, bl.position.x-240, bl.position.y);

}

De momento solo sale el personaje y los bloques. La única interacción es conseguir que el personaje no pueda entrar en las paredes. Esto ha sido un poco lío pero al final parece que va bien. La estrategia es seguir estos pasos:
  1. Mover la componente x del personaje a las bravas.
  2. Comprobar si colisiona con algún bloque.
  3. Si colisiona retrocedemos un poco y volvemos al punto 2.
  4. Lo mismo con la componente y.
Aunque suene lógico y sencillo hay muchas variables en juego y el equilibrio es frágil.

Queda muchísimo camino para que esto pueda ser llamado juego. Al menos el primer paso ya está hecho. Ahora hay que tomar decisiones sobre la jugabilidad, sobre el concepto, el arte, diseño de niveles, secciones, ayuda, música, animaciones, puntuación, vidas, marcador, optimización... y mil cosas más.

Quien quiera probarlo y modificarlo puede seguir los pasos del post anterior. Si solo queréis probarlo podéis ir a esta dirección desde un móvil android: Descargar juego NoWhereGame. Por supuesto lo hacéis bajo vuestra responsabilidad. Esta app puede derretir tu dispositivo y atropellar a tu gato.

El control del personaje de momento consiste en tocar la pantalla por abajo a la derecha o a la izquierda para ir en esa dirección y tocar por arriba para saltar. No se puede parar.

He estado a punto de poner aquí un pantallazo pero si no lo pongo es ligeramente más probable que lo instaléis.

miércoles, 17 de abril de 2013

Programando para android - 1. Inicio

Voy a iniciar otra serie (incluso sin haber acabado la del pedal, qué nivel) para poner en marcha un pequeño juego para android. La motivación es practicar un poco el java que lo tengo peor que oxidado. El hecho de ponerlo aquí en el blog me sirve para no dejarlo abandonado a la primera de cambio y para que os apuntéis los que estéis interesados en trastear un poco todo este tinglado.

He decidido usar una librería que parece interesante libgdx, sirve para facilitar un poco las cosas típicas de juegos como la gestión de los gráficos, la música, etc... y además se encarga de que el resultado sea compatible con pc, android, web y iphone. Para quien se apunte aquí está lo que hay que instalar previamente y aquí posteriormente.

Para iniciar el proyecto y preparar todos los archivos y dependencias viene un pequeño ejecutable (gdx-setup-ui.jar) que genera el esqueleto inicial:


Después voy a importarlos a Eclipse mediante Import => Existing project into workspace. Aquí ya podríamos empezar a picar pero si somos un poco elegantes preferiremos...

Ponerlo en sistema de control de versiones: He usado el subclipse para subirlo a code google goingnowhere. Ahí ya podéis ver el código inicial generado que es una especie de Hola mundo. Para verlo en funcionamiento hay que compilarlo en el Eclipse. Es muy útil lo de que se compile por igual en varias plataformas, no será necesario abrir un emulador de android ni conectar un dispositivo en modo debug porque simplemente podemos ejecutar la versión PC que es más directo y sabemos que luego funcionará también en las otras versiones.

Al ejecutar se muestra esto:

Una pantalla de inicio sencilla que muestra una imagen.

Si solo queréis probar (y colaborar) justo esta aplicación que he colgado los pasos se reducen y se simplifican:
  • Instalar el JDK de Java.
  • Instalar el ADT-Bundle de google (que lleva eclipse + un montón de cosas necesarias).
  • Añadir el plugin subeclipse al Eclipse en Help => Install new software y en Work with ponemos la dirección  http://subclipse.tigris.org/update_1.8.x e instalamos los paquetes que aparecerán.
  • Importar mi proyecto mediante File => Import =>SVN => y ponemos la url https://goingnowhere.googlecode.com/svn/trunk
Para probar si funciona hacéis botón derecho en la carpeta goingnowhere-desktop y vais a Run as => Java Aplication (y marcáis el Main si lo pregunta).