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...


10 comentarios:

koco dijo...

Deberías pensar en poner al demonio de kgontí como protagonista del juego.

Baterpruf dijo...

Pues ya sabes.
Necesitaría sprites de la resolución que quieras pero que se vean bien al redimensionarlos a 32x32 píxels. Y puestos a pedir iría bien dibujos en las diferentes posiciones parado, saltando, ciclo de andar o de correr, disparar... es un poco pronto porque aún no sé si llevará arma o no pero siempre se podría añadir, no?

koco dijo...

Posición parado:

- parado





Posición nadando:

- nadando



Posición disparando:

- disparando

Baterpruf dijo...

Vaya... y yo pensando que ibas a colaborar...

http://i219.photobucket.com/albums/cc12/sirkillsalotlol/TROLLS-TROLLS-EVERYWHERE-1.jpg

kpacha dijo...

muy buen análisis!

tienes toda la razón: si sólo vas a tener un mapa, el tema del peso pierde importancia.

si crees que la descripción tiene que hacerse por 'celda', mi versión inicial del archivo de texto plano ya sería de 147bytes sin zipear pq yo utilizaría un formato más parecido al del fax. así, tu mapa podría describirse como:

28X
1X,26.,1X
1X,26.,1X
1X,26.,1A,1.,1X
1X,23.,4X
1X,23.,4X
2X,22.,4X
1X,23.,4X
2X,1.,1B,20.,4X
1X,23.,4X
10X,12.,4X
10X,12.,4X
10X,12.,4X
28X
28X

aunque me da a mi q si describimos el escenario sólo por las cosas que hay y no por las que no hay, nos ahorraríamos del orden de unos 50bytes más (q es lo q ocupa la descripción de los espacios en blanco). si encima tenemos en cuenta que el 'marco' del mapa siempre va a estar ahí, el ahorro se va incrementando. Sólo son importantes las variaciones dentro de un mapa 28x15 con 'X' en los bordes y el interior totalmente blanco.

de todas formas, si dices que se puede embeber directamente para que haga de minimapa, entonces usar el png va ganando sentido.

lo q no pillo es eso de q "Pero también habría que programar toda la lectura y análisis del archivo mientras que ahora es una única línea"... la lectura se hace en una línea, pero luego tienes q parsear igualmente el contenido!

kpacha dijo...

como decía:

(4,27)1A
(7,1)1X
(9,1)1X,(9,3)1B
(11,1)9X
(11,1)9X

sirve para describir este mapa de 28x15 completamente y en sólo 50 bytes. y todavía es muy mejorable

kpacha dijo...

fe de ratas: en mi anterior comentario había un typo... el mapa se describiría así

(4,27)1A
(7,1)1X
(9,1)1X,(9,3)1B
(11,1)9X
(12,1)9X
(13,1)9X

... y sí, son 60bytes en vez de 50.

kpacha dijo...

fe de ratas 2: me acabo de dar cuenta de que no he corregido todos los fallos... espero q no os pongáis muy quisquillosos con el tema de las posiciones, pero es q inicialmente lo había preparado para una rejilla de 30x15 y se me han escapado algunas cosillas como por ejemplo el posicionamiento del objeto A.

para el caso es lo mismo, pq lo q importa aquí es el peso de la descripción...

Baterpruf dijo...

Esa codificación del texto que propones es cierto que está muy bien para que ocupe menos pero sería un peñazo para el diseño de niveles. Lo típico será unas 30 fases y deberían de estar muy bien planificadas para que sean entretenidas, moderadamente difíciles, etc. Para ello habrá que ir testeando muchas variantes y luego ir haciendo muchos pequeños cambios. Para eso es mucho más visual crearlo en modo imagen o al menos con el texto expandido con los espacios.

Por otra parte si tengo 30 fases que en vez de ocupar 150B ocupan 50B... ahorro 3KB en total. Cualquiera de los sonidos o imágenes incluidos en el juego va a ocupar más que eso. Las apps vienen ocupando de un MB para arriba.

Pero si al final resulta que quiero ahorrarme esos 3KB siempre puedo convertir los pngs a ese formato o similar aunque solo fuera para la exportación final.

kpacha dijo...

otra vez te doy la razón: los archivos 'optimizados' no son prácticos durante el desarrollo. Por eso se suele montar algún componente para delegar la conversión del modo 'legible' al modo 'optimizado'. se hace lo mismo con las librerías de javascript!

otra ventaja de este sistema es q puedes describir TODOS los escenarios en un único archivo, con el consiguiente ahorro de pasar de 30 archivos de 60bytes a 1 de 1.8Kbytes que seguro que se zipea de miedo.

otra ventaja más: fácilmente podrías hacer q los escenarios fuesen colaborativos poniendo un servidor a gestionar el catálogo de escenarios... y, además de ser más 'sencillo' servir texto q imágenes, teniendo en cuenta q se paga por bytes almacenados y transferidos, cualquier ahorro es bueno. Si piensas en un único usuario no tiene sentido. Pero cuando el número de peticiones aumenta, ahorrarse el 60% de los costes no es ninguna tontería!

pero como siempre, si el coste no compensa los beneficios, la inversión no vale la pena.