Formato de archivo extensible personalizado para mapas en mosaico 2D


8

He implementado gran parte de mi lógica de juego en este momento, pero sigo creando mis mapas con for-bucles desagradables sobre la marcha para poder trabajar con algo. Ahora quería seguir adelante e investigar un poco sobre cómo (des) serializar estos datos. (No busco un editor de mapas, estoy hablando del archivo del mapa en sí)

Por ahora estoy buscando sugerencias y recursos, cómo implementar un formato de archivo personalizado para mis mapas que debería proporcionar la siguiente funcionalidad (basada en el método MoSCoW):

  • Debe tener
    • Extensibilidad y compatibilidad con versiones anteriores.
    • Manejo de diferentes capas.
    • Metadatos sobre si un mosaico es sólido o se puede pasar
    • Serialización especial de entidades / disparadores con propiedades / metadatos asociados
  • Podría tener
    • Algún tipo de inclusión del conjunto de mosaicos para evitar tener archivos / mosaicos dispersos

Estoy desarrollando con C ++ (usando SDL) y apuntando solo a Windows. Cualquier ayuda útil, consejos, sugerencias, ... sería apreciada!


Resultado de la discusión a continuación

He estado diseñando mi formato de archivo de mapa las últimas horas y se me ocurrió un esqueleto (contiene solo capas por ahora; dejaré el resto a todos los que diseñen su propio formato) que quería compartir con todos los interesados, si tienes las mismas intenciones, puedes obtener algún tipo de inspiración. La captura de pantalla a tamaño completo se puede descargar en Imgur .

Formato de archivo de mapa Kore


2
XML es un formato excelente para comenzar, es extensible, compatible con versiones anteriores, puede agregar cualquier información y metadatos que desee. Existe un amplio soporte para leer, crear y editar XML. El soporte para serializar hacia y desde XML existe para casi todos los idiomas. La desventaja es que es poco eficiente en cuanto al espacio, esto puede mejorarse usando una versión binaria o usando compresión zip en el archivo mismo. Sin embargo, es un buen punto de partida para crear sus propios formatos de archivo
Daniel Carlsson

@DanielCarlsson: Como se menciona en la respuesta aceptada a continuación, me quedaré con XML al principio para tener algo útil para depurar y trabajar. Más adelante pasaré a un formato binario personalizado. Sin embargo, votó porque XML es increíble en combinación con las bibliotecas RapidXML en C ++.
Christian Ivicevic

Respuestas:


6

Personalmente, soy más fanático de los formatos binarios con secciones (como Windows PE, pero mucho más simple). También son más fáciles de analizar (pero esa es solo mi opinión ... Trabajé con XML lo suficiente como para darme dolores de cabeza, comprobando si getElementByName ha devuelto un solo valor o una lista de valores ... ugh). Entonces, si yo fuera tú, lo haría algo como esto:

".MMF\0" // magic value at the start, null-terminated string. stands for My Map Format :)
    char header_length // useful when parsing. char is a byte, of course, an unsigned one
    char version // version of the map file. (you don't really need ints here, because you probably won't be needing more than 255 versions for example, but you can also use them)
    char* map_name // null terminated string describing the name of the level/map
    char* author_name // if you are going to have a map editor for the general public, it would be nice to credit the person who made the map
    int width // it's probably wise to plan ahead and expect an int here when you're parsing the file
    int height
    ".layer\0" // we begin another subsection
        char header_length
        char type // type of the layer. for example, you can put 1 there if you want this to be a layer describing different tiles/block in a Terraria like game
        ".data\0" // yet another subsection. this will hold the data for the tiles
                  // in a hypothetical terraria 2d game, you would lay down tiles from
                  // the top-right corner (0,0) and then begin writing row after row
                  // write(1,0); write(2,0); write(3,0); ... then write(0,1); write(1,1);
                  // write(2,1); write(3,1); and so on..
            char t1 // tile at (0,0). for example, value 0 is empty, or passable tile
            char t2 // tile at (1,0). this might be a dirt block - value 1
            char t3 // tile at (2,0). a rock, perhaps? value 3
            (...)
            char tn // tile at (width-1, height-1) or the bottom-left tile
    ".layer\0" // another layer.
        char header_length    
        char type // let this on be of value 2, and let it describe portals.
                  // putting portals in a game makes it instantly 20% cooler
        ".data\0"
            char t1  // 0, no portal here at tile (0,0)
            char t2  // still nothing
            char t3  // nope, try again
            (...)
            char t47 // at some location, you made a red portal. let's put 1 here so we can read it in our engine
            (...)
            char t86 // looke here, another 1! you can exit here from location corresponding to t47
            (...)
            char t99 // value 2. hm, a green portal?
            (...)
            char tn  // bottom-left tile, at (width-1, height-1)
    ".layer\0" // another layer
        char header_length
        char type // value 3, player&enemies spawn points
        char something // you don't have to have header len fixed. you can add stuff later
                       // and because you were smart enough to put header length 
                       // older versions can know where the stuff of interest lays
                       // i.e. version one of the parser can read only the type of layer
                       // in version two, you add more meta-data  and the old parser
                       // just skips it, and goes straight to the .data section
            ".data\0"
                char t1  // zero
                char t2  // zero
                char t3  // zero
                (...)
                char t42 // a 1 - maybe the player spawn point. 5 tiles to the right
                         // there's a red portal
                (...)
                char t77 // a 2: some enemy spawn point
                (...)
                char tn  // last tile

,

Ventajas:

  • Se ve bien.
  • Te hace pensar que sabes algo sobre programación, hacer cosas a la antigua usanza.
  • Puede escribir manualmente sus niveles en un editor hexadecimal:
  • Generalmente más rápido que INI y XML, tanto desde la perspectiva de escritura como de lectura
  • Es una larga secuencia de datos de bytes, en realidad. No es necesario dedicar tiempo a hacer que se vea bonita, con sangría (como lo que le gustaría hacer con XML).
  • Es fácil agregar cosas en los encabezados. Si una parte de los datos aparece en la parte inferior del encabezado, se puede indicar a las versiones antiguas de analizadores que eviten y salten a la parte del archivo que entienden.

Desventajas

  • Debe cuidar bien la ubicación de los datos.
    • Los campos de datos deben ser ordenados.
    • Debes saber su tipo en el analizador, como dije, es solo una larga secuencia de bytes.
    • Mover datos por una ubicación (por ejemplo, se olvida de escribir el tipo de capa; el analizador espera un byte allí y encuentra el valor de '.' - eso no es bueno) desordena toda la matriz de datos desde ese punto en adelante.
  • Es más difícil saltar directamente: no hay API, no hay función como getLayerWidth (), tiene que implementar todo eso usted mismo.
  • Potencialmente hay mucho espacio desperdiciado. Tome la tercera capa, por ejemplo. Ciertamente estará lleno de ceros. Sin embargo, esto puede evitarse si usa algún tipo de compresión. Pero una vez más, eso está jugando con cosas de bajo nivel una vez más ...

Pero lo mejor de este enfoque en mi opinión es: puedes hacerlo todo por ti mismo. Muchas pruebas y errores, pero al final, terminas aprendiendo mucho.


Solo está guardando ... digamos ID para los mosaicos, pero ¿qué pasa con sus metadatos? ¿Cómo debo guardar si los azulejos son transitables o no? ¿Qué pasa con los disparadores e incluso las secuencias de comandos / código / llamadas de función asociadas con ellos?
Christian Ivicevic

@ChristianIvicevic: Hay varias maneras de hacerlo:
Vladimir Mitrovic, el

@ChristianIvicevic: 1. Empaque los metadatos en un solo byte. ¿Solo tienes ocho fichas posibles? Genial, guarda el resto cinco bits para otra cosa. En tu caso, preguntaste sobre los azulejos transitables. Puede hacer que el primer bit (bit 0) almacene esa información. Un poco de manipulación de bits :) hará el truco ( codepad.org/Q6zfTV44 ). 2. Use capas para eso. Tenga una capa con un tipo único y complétela con ceros y unos, unos para transitables y ceros para fichas intransitables. 3. Use más de un byte por mosaico. Un byte para el valor, el otro para los metadatos.
Vladimir Mitrovic

@ChristianIvicevic: en cuanto a los scripts, supongo que ha implementado un analizador de scripts que funciona. Puede agregar una sección a su archivo de mapa y ponerlos allí: pastebin.com/yUKncz19 O bien, puede ponerlos en un archivo separado y guardar un nombre de archivo en la sección ".scripts". Luego, antepone otra sección ".layer" que describe qué mosaicos activan qué secuencia de comandos: pastebin.com/BgPCR2xQ
Vladimir Mitrovic

Un montón de ejemplos: ¡TOP! Ahora me atendré a XML para crear algunos niveles básicos para depurar / trabajar y eventualmente pasaré a un formato binario que describiste para el archivo de mapa sin procesar que contiene los datos y empacaré este archivo con los mosaicos (png, etc.) y los scripts en un zip para tener todo estructurado de mejor manera. Dependerá de escribir código, que en realidad lee esos datos binarios, pero ese es otro tema en mi historia ... ¡gracias!
Christian Ivicevic

9

Puede utilizar el formato de mapa TMX utilizado por el editor de mosaico (así como por varios otros editores de mapas).

Incluso si no utiliza Tiled usted mismo, el formato TMX admite todas las funciones que mencionó y tiene varios cargadores / analizadores existentes para una variedad de idiomas. También es muy fácil entender el formato y extenderlo para tu propio juego.


Tendré mi concepto XML actual basado un poco en el formato de mapa TMX y luego leeré todos los archivos con RapidXML; más adelante pasaré a algún formato de archivo binario personalizado.
Christian Ivicevic
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.