Página 1 de 2

Formato que genera mapcnv

Publicado: Jue, 09 Jul 2015, 12:04
por Javi Perez
Hola,

He dado por casualidad con un turorial en EMS donde explicáis como usar la herramienta mappy y debo decir que ha sido una revelación. Estoy haciendo pruebecillas con Z88DK y me estaba montando un mapa a mano con un par de tiles de prueba que he creado. Pero la tarea es muy tediosa y creo que mappy puede venir de perlas. Lo que necesito es muy simple, algo que me permita definir qué tile se ha de colocar en cada grid del mapa.

Primera pregunta, probablmente estúpida, es si se puede usar el mappy y el mapcnv para juegos que no se programen con la Churrera. Entiendo que sí, pero no estoy seguro de sí hay alguna característica ad-hoc que impidan usarlas fuera de esos entornos.

La segunda pregunta es sobre el formato del array que se encuentra dentro del fichero mapa.h generado por mappy. Entiendo que el array contiene IDs de tiles pertenecientes a algún tileset, pero no lo tengo claro...A modo de ejemplo, este array de uno de vuestros juegos, Dogmole creo:
$this->bbcode_second_pass_code('', '
unsigned char mapa [] = {
119, 119, 119, 119, 119, 119, 119, 119, 0, 0, 0, 0, 0, 0, 0, 112,...
')

Gracias!

Re: Formato que genera mapcnv

Publicado: Jue, 09 Jul 2015, 12:44
por na_th_an
Buenas.

Mapcnv te sirve para coger los datos que exporta mappy en formato "raw" (sin cabeceras, sólo un byte por tile del mapa; si no sabes cómo configurarlo mejor que te bajes el mappy mojono, que viene preparado -> https://www.mojontwins.com/warehouse/Mappy-mojono.rar) cuando grabas el mapa con extensión ".map" y dividirlo en pantallas.

Mappy exporta todo el mapa como un rectángulo de tiles gigante. Si tienes un mapa de 4x4 pantallas y cada pantalla es de 10x10 tiles, lo que exporta mappy es un rectángulo de 40x40 tiles ordenados por filas. Si estás haciendo un juego por pantallas es más cómodo tener los tiles de cada pantalla "juntos", por lo que hay que reordenar esa información.

Mapcnv hace eso. Recibe como parámetros las dimensiones del mapa en pantallas y las dimensiones de cada pantalla en tiles y toma el rectángulo de mappy y reorganiza los datos. En el array generado, y siguiendo con el ejemplo de 10x10 tiles en 4x4 pantallas, primero irán los 100 tiles de la primera pantalla, luego los 100 de la segunda... y así hasta la decimosexta. Para pintar una pantalla sólo te tienes que ir a la posición N*100 y pintar 100 tiles a partir de ahí.

Los datos que has puesto usan un formato empaquetado en el que cada byte contiene dos tiles. Cuando sólo hay 16 tiles, se usan 4 bits para cada tile y por tanto en un byte podemos meter dos, con lo que el mapa ocupa la mitad. Eso se consigue con el parámetro PACKED. Obviamente si usas más de 16 tiles no puedes empaquetar así.

Aunque no vayas a usar la churrera, es bueno que te leas el capítulo del tutorial donde se explica cómo se maneja Mappy y se usa mapcnv, y lo adaptes a tus necesidades.

Re: Formato que genera mapcnv

Publicado: Jue, 09 Jul 2015, 19:54
por Javi Perez
$this->bbcode_second_pass_quote('na_th_an', '
')Aunque no vayas a usar la churrera, es bueno que te leas el capítulo del tutorial donde se explica cómo se maneja Mappy y se usa mapcnv, y lo adaptes a tus necesidades.

Muchas gracias por el consejo, acabo de leer ese capítulo y creo que el Mappy tal y como lo tenéis compilado me sirve perfectamente.

Por otro lado, a raíz de haber generado el mapa y tratar de renderizarlo con las funciones de la SP1, no sé si he dado con un bug, o una limitación de la librería, o me quedado sin memoria o que se yo :x :x :x

He definido un tile de prueba 16x16 con el que quiero "forrar" una pantalla entera. Para ello he dimensionado el array del mapa para almacenar los 192 tiles de 16x16. El problema que me encuentro es que sólo puedo pintar 38 tiles. A partir del 39 el programa peta. ¿Existe alguna limitación en cuanto al número máximo de tiles que se pueden pintar simultáneamente con SP1?

Re: Formato que genera mapcnv

Publicado: Jue, 09 Jul 2015, 23:44
por na_th_an
38 es un número raro, deberías mirar qué puede estar pasando.

No sé si SP1 funciona al respecto igual que splib2, en el caso de que sí lo haga el tema es que se puede definir sólo 256 caracteres para el fondo. Si usas 64 de esos para la fuente (los símbolos y las mayúsculas, qué menos, del 32 al 95 en ASCII), te quedan 192 para hacer tiles. Si usas tiles de 16x16 y no mapeas los tiles, usas 4 caracteres por tile, con lo que el máximo son 48 diferentes.

Es posible que SP1 use dos bytes por caracter y permita 65536 (lo digo porque sé que hay un modo de usar un screen$ de fondo y esta es la única forma), pero eso se lo tendrías que preguntar a su autor o a cualquiera de los programadores que lo usa, como Timmy en WOS. Busca a Alcoholicus Annonymous en WOS, siempre responde todas las preguntas con muchísimo detalle. A mí me ayudó muchísimo hace mil, cuando empezaba con splib2 :)

Re: Formato que genera mapcnv

Publicado: Vie, 10 Jul 2015, 08:43
por Javi Perez
$this->bbcode_second_pass_quote('na_th_an', '3')8 es un número raro, deberías mirar qué puede estar pasando.

No sé si SP1 funciona al respecto igual que splib2, en el caso de que sí lo haga el tema es que se puede definir sólo 256 caracteres para el fondo. Si usas 64 de esos para la fuente (los símbolos y las mayúsculas, qué menos, del 32 al 95 en ASCII), te quedan 192 para hacer tiles. Si usas tiles de 16x16 y no mapeas los tiles, usas 4 caracteres por tile, con lo que el máximo son 48 diferentes.

Es posible que SP1 use dos bytes por caracter y permita 65536 (lo digo porque sé que hay un modo de usar un screen$ de fondo y esta es la única forma), pero eso se lo tendrías que preguntar a su autor o a cualquiera de los programadores que lo usa, como Timmy en WOS. Busca a Alcoholicus Annonymous en WOS, siempre responde todas las preguntas con muchísimo detalle. A mí me ayudó muchísimo hace mil, cuando empezaba con splib2 :)


Bueno, realmente más que un fondo de caracteres, como no controlo mucho de momento lo que estoy haciendo es pintar sprites en toda la pantalla:

$this->bbcode_second_pass_code('', '
#define NUM_TILES_PANT 192

struct tile
{
struct sp1_ss *pTile;
enum TipoTiles iTipo;
};

struct tile pant_tile[NUM_TILES_PANT];
')
Y luego tengo un bucle hasta NUM_TILES_PANT donde en cada iteración simplemente se pinta un bloque de 16x16 definido en datos_pared:
$this->bbcode_second_pass_code('', '
pant_tile[i].pTile = sp1_CreateSpr(SP1_DRAW_MASK2LB, SP1_TYPE_2BYTE, 3, 0, 1);
sp1_AddColSpr(pant_tile[i].pTile, SP1_DRAW_MASK2, 0, 48, 1);
sp1_AddColSpr(pant_tile[i].pTile, SP1_DRAW_MASK2RB, 0, 0, 1);
sp1_MoveSprAbs(pant_tile[i].pTile, &cr, datos_pared, y, x, 0, 0);

pant_tile[i].iTipo = BLOCK;
')
En este bucle es donde comentaba que al llegar a la iteración 38, la cosa peta...

Re: Formato que genera mapcnv

Publicado: Vie, 10 Jul 2015, 09:11
por na_th_an
Es que usar sprites para cubrir una pantalla es un poco overkill... En splib2, cada sprite ocupa 15 bytes de memoria dinámica por cada bloque que usa más un bloque más. O sea, un sprite de 16x16 que usa 9 bloques ocuparía 150 bytes. Estoy seguro de que en SP1 ocupan incluso más. 38 sprites son ya 5700 bytes, un pasote. Los 192 sprites que quieres poner ocuparían más de 28K de tu pool de memoria dinámica.

Por lo general cuando haces un juego estás bastante apretado (y con SP1 mucho más, por eso nunca me he decidido a pasarme), así que lo suyo es contar como un avaro cada bloque de memoria dinámica que vas a usar. En MK2 por ejemplo se reserva justo la memoria que se necesita para justos los sprites del tamaño justo que se va a necesitar en el juego. Para un juego normal, por ejemplo, de 4 sprites de 16x16 y 3 disparos de 8x8 reservamos 4*10+3*5=55 bloques, o sea, 55*15=825 bytes, y ni uno más. Hay que mirar mucho por la memoria.

Además, la velocidad de proceso de cada frame del juego si usas sprites de fondo puede ser REALMENTE lenta.

Para rellenar la pantalla hay que usar tiles de fondo del charset. Los sprites déjalos para cosas que se muevan. Los tiles sólo ocupan un par de bytes que ya están reservados en la tabla de tiles, dentro del binario estático que genera el compilador.

Re: Formato que genera mapcnv

Publicado: Vie, 10 Jul 2015, 10:50
por Javi Perez
$this->bbcode_second_pass_quote('na_th_an', 'P')ara rellenar la pantalla hay que usar tiles de fondo del charset. Los sprites déjalos para cosas que se muevan. Los tiles sólo ocupan un par de bytes que ya están reservados en la tabla de tiles, dentro del binario estático que genera el compilador.

Pero entonces...cuando en Mappy cargamos un tileset y posteriormente generamos el array unsigned char mapa[] con mapcnv, ¿internamente el motor no genera sprites por cada unos de los bytes de mapa[]?

Re: Formato que genera mapcnv

Publicado: Vie, 10 Jul 2015, 11:03
por na_th_an
No.

Tienes que tener muy clara la diferenciación de los elementos que componen el display. Es muy importante.

splib2 y SP1 funcionan emulando el modo de funcionamiento de los chips gráficos de las consolas (la mayoría de las de 3ª y 4ª generación: NES, Master System, Megadrive, SNES...) y de algunos ordenadores como C64 o MSX. La pantalla no se considera un framebuffer o un array de pixels, sino que está formada por una rejilla de tiles de fondo y un número de sprites que se mueven sobre dicha rejilla, sin alterar el fondo. Como el Spectrum no es capaz de hacer eso por sí solo, splib2 y SP1 le proporcionan una solución software para comportarse así.

Un sprite es un elemento móvil, formado por un número de bloques de 8x8 pixels (en otros entornos, como cuando programas un chip gráfico de una consola, se llama "metasprite" porque los sprites, son, en realidad, las unidades básicas, en este caso cada cuadro de 8x8 que lo compone). Cada bloque almacena su posición, atributos y propiedades, y un enlace a información con el gráfico y su máscara. O sea, por cada cuadro de 8x8 se almacenan muchos bytes (en splib2, 15 en concreto), que son necesarios para poder cambiarlo de posición y poder restaurar el fondo que tiene debajo, entre otras cosas.

Un tile es un elemento fijo. La pantalla se divide en una rejilla de 32x24 tiles (correspondientes a los caracteres) de 8x8 pixels. Para cada celda de la rejilla se define un número de tile y su color. Es lo que se utiliza como fondo, porque un tile no se va a mover de su sitio y la información que se precisa almacenar es mínima.

El "charset" o "tileset", como quiera llamarse, es un número discreto de gráficos de 8x8, cada uno con un identificador o número de orden. En el tileset, la rejilla de fondo, se contienen los números que identifican a cada tile del charset, no el gráfico en sí. Por eso, el fondo únicamente puede estar compuesto por los gráficos del charset. Dependiendo del hardware o de la biblioteca que se use por software, este número varía. Por ejemplo, en NES o splib2 son 256. En Megadrive son algo más de 1500.

Cuando montamos una escena con una de estas bibliotecas, o con un chip gráfico basado en tiles y sprites, definimos un diseño dándole valores del charset a la rejilla de tiles y luego creamos un número de sprites que se muevan sobre la rejilla para representar al personaje, los enemigos, los proyectiles... las cosas que se mueven.

Lo que se exporta con mapcnv no es más que una colección de los metatiles que componen cada pantalla. Un metatile se define como un rectángulo de tiles que se considera una unidad. Por ejemplo, en la Churrera y en MK2, cada pantalla está compuesta por 150 metatiles en un rectángulo de 15x10, y cada metatile tiene un tamaño de 16x16 pixels, por lo que debe estar compuesto por 2x2 tiles de la rejilla de tiles que maneja la biblioteca.

El motor lee el array y dibuja sobre la rejilla cada uno de los metatiles según se los va encontrando, colocando los cuatro tiles que forman cada metatile según el índice que encuentre en el array. En la Churrera y MK2 el proceso es muy sencillo ya que cada metatile siempre está compuesto por cuatro tiles de id secuencial, empezando por el tile 64 del charset. O sea, cada vez que vamos a pintar un metatile que en el array está referenciado con el número "N", en realidad estamos pintando los tiles de charset de números 64+N*4, 64+N*4+1, 64+N*4+2 y 64+N*4+3, los dos últimos debajo de los dos primeros.

Esto se hace para ahorrar memoria. El área de juego de nuestros motores es de 240x160 pixels, o lo que es lo mismo, 30x20 caracteres. Eso ocuparía 600 bytes. Usando metatiles de 2x2 caracteres, perdemos algo de libertad para confeccionar las escenas, pero sólo necesitamos 15x10 metatiles que ocupan 150 bytes, o sea, la cuarta parte. Si, además, usamos sólo 16 metatiles diferentes para hacer nuestro mapa, vemos que en cada byte podemos meter dos, con lo que cada pantalla pasa a ocupar sólo 75 bytes. De esa forma, 10 pantallas pasarían de ocupar 6000 bytes a ocupar sólo 750, algo muy importante cuando se programa para máquinas tan limitadas.

Re: Formato que genera mapcnv

Publicado: Vie, 10 Jul 2015, 11:18
por na_th_an
Aunque no me gusta demasiado cómo resuelve algunas cosas, creo que los últimos capítulos del curso que se publicó en tiempos en Magazine ZX es buena introducción a este sistema de organización de la pantalla. Échale un vistazo a este PDF que recopiló Radastan, a partir de la página 93 http://www.bytemaniacos.com/ficheros/zx ... /z88dk.pdf

Re: Formato que genera mapcnv

Publicado: Vie, 10 Jul 2015, 11:50
por Javi Perez
$this->bbcode_second_pass_quote('na_th_an', 'A')unque no me gusta demasiado cómo resuelve algunas cosas, creo que los últimos capítulos del curso que se publicó en tiempos en Magazine ZX es buena introducción a este sistema de organización de la pantalla. Échale un vistazo a este PDF que recopiló Radastan, a partir de la página 93 http://www.bytemaniacos.com/ficheros/zx ... /z88dk.pdf


Muchas gracias por las explicaciones tan detalladas. Realmente esaba haciendo una burrería utilizando sprites para rellenar el fondo. He mirado el PDF, pero está escrito pensando en splib, y en SP1 funciones como "sp_PrintAtInv()" ya no están soportados. En cualquier caso, ,o miraré con detalle a ver cómo se soluciona en SP1.

Mil gracias por tu tiempo y por proporcionar tanto detalle!