2Dタイルマップのカスタム拡張ファイル形式


8

現在、ゲームロジックの多くを実装していますが、何かを操作できるように、オンザフライで厄介なforループを使用してマップを作成しています。次に進んで、このデータを(非)シリアル化する方法についていくつかの調査を行いたいと思いました。(私はマップエディターを検索しません-私はマップファイル自体について話しています)

現時点では、提案とリソース、次の機能を提供する(MoSCoWメソッドに基づく)マップにカスタムファイル形式を実装する方法を探しています。

  • 持つ必要があります
    • 拡張性と下位互換性
    • 異なるレイヤーの処理
    • タイルが固体であるか通過できるかに関するメタデータ
    • 関連するプロパティ/メタデータを持つエンティティ/トリガーの特別なシリアル化
  • 持つことができた
    • ファイル/タイルセットが散らばらないようにするためのタイルセットのある種の包含

C ++(SDLを使用)で開発しており、Windowsのみをターゲットにしています。役立つヘルプ、ヒント、提案などがあれば、よろしくお願いします!


以下の議論の結果

私は過去数時間にマップファイル形式を設計していて、スケルトン(今のところレイヤーのみが含まれている-残りは彼/彼女の独自の形式を設計しているすべての人に任せる)を考えた。同じ意図があり、何らかのインスピレーションを得ることができます。フルサイズのスクリーンショットはImgurからダウンロードできます。

コレマップファイルフォーマット


2
XMLはそもそも素晴らしいフォーマットであり、拡張可能であり、下位互換性があるため、必要な情報やメタデータを追加できます。XMLの読み取り、オーサリング、編集には幅広いサポートがあります。XMLとのシリアライズのサポートは、ほぼすべての言語に対応しています。欠点は、スペース効率がかなり悪いことです。これは、バイナリバージョンを使用するか、ファイル自体にzip圧縮を使用することで改善できます。それでも、独自のファイル形式を作成するための良い出発点です
Daniel Carlsson

@DanielCarlsson:以下の受け入れられた回答で述べられているように、私は最初にXMLに固執し、デバッグや作業に役立つものを用意します。後で、カスタムバイナリ形式に移ります。それにもかかわらず、XMLはC ++のRapidXMLライブラリと組み合わせると素晴らしいので賛成です。
クリスチャンIvicevic

回答:


6

個人的には、セクションを含むバイナリ形式のファンの方が好きです(Windows PEのように、はるかに単純です)。それらは解析も簡単です(しかし、それは私の意見ですが... getElementByNameが単一の値を返したか、値のリストを返したかどうかをチェックして、頭痛の種になるほどXMLで作業しました...うーん)。だから、もし私があなたなら、私はそれをこのようなものにしたいと思います:

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

利点:

  • かっこいいね。
  • プログラミングについて何かを知っていると思い込ませ、昔ながらの方法で物事を行う。
  • 16進エディターでレベルを手動で書き込むことができます。
  • 書き込みと読み取りの両方の観点から、一般にINIやXMLよりも高速
  • 本当に、それはバイトデータの長いストリームです。見栄えをよくするために時間をかける必要はありません。
  • ヘッダーに内容を追加するのは簡単です。データの一部がヘッダーの下部にある場合、古いバージョンのパーサーにそれを回避して、理解できるファイルの部分にジャンプするように指示できます。

短所:

  • データの配置には十分注意する必要があります。
    • データフィールドは順序付けする必要があります。
    • パーサーでそれらのタイプを知っている必要があります-私が言ったように、それは単にバイトの長いストリームです。
    • データを1つの場所に移動すると(たとえば、レイヤーのタイプを書き込むのを忘れた場合、パーサーはそこに1バイトを期待し、「。」の値を検出します-これは適切ではありません)、データアレイ全体を混乱させます。
  • すぐにジャンプするのは困難です-APIやgetLayerWidth()のような関数はありません-これらすべてを自分で実装する必要があります。
  • 潜在的に多くの無駄なスペースがあります。たとえば、第3層を見てみましょう。それは確かに多くのゼロでパックされます。ある種の圧縮を使用すれば、これを回避できます。しかし、繰り返しますが、それは低レベルのものに再び混乱しています...

しかし、私の考えでは、このアプローチの最良の点は、自分ですべてを実行できることです。試行錯誤はたくさんありますが、最終的には多くのことを学ぶことになります。


保存しています...タイルのIDについて考えてみましょう。ただし、メタデータについてはどうでしょうか。タイルが通過可能かどうかをどのように保存すればよいですか?トリガーについてはどうでしょうか?トリガーに関連付けられたスクリプト/コード/関数呼び出しについても同様です。
Christian Ivicevic

@ChristianIvicevic:これを行うにはいくつかの方法があります:
Vladimir Mitrovic

@ChristianIvicevic:1.メタデータを1バイトにパックします。タイルは8つしかありませんか?残りの5ビットを別の何かのために保存します。あなたの場合、通過可能なタイルについて尋ねました。最初のビット(0番目のビット)にその情報を格納させることができます。少しビット操作:)がトリックを行います(codepad.org/Q6zfTV44)。2.そのためにレイヤーを使用します。固有のタイプのレイヤーを用意し、ゼロと1で埋めます。1は通過可能タイル、0は通過不可タイルです。3.タイルごとに複数のバイトを使用します。値用に1バイト、メタデータ用にもう1バイト。
Vladimir Mitrovic 2012

@ChristianIvicevic:スクリプトについては、動作するスクリプトパーサーを実装したと思います。あなたのマップファイルにセクションを追加し、そこにそれらを置くことができます。pastebin.com/yUKncz19 か、別のファイルに入れて、「.scripts」セクションでファイル名を保存することができます。:あなたはその後、どのスクリプト火タイル記述する別の「.layer」セクション先頭に追加pastebin.com/BgPCR2xQ
ウラジミールMitrovic

かなりたくさんの例-TOP!次に、XMLに固執して、デバッグ/処理するためのいくつかの基本レベルを作成し、最終的に、データを保持する未加工のマップファイルについて説明したバイナリフォーマットに進み、このファイルをタイルセット(pngなど)とパックします。スクリプトファイルをzipに変換して、すべてをより適切に構造化します。実際にそのようなバイナリデータを読み取るのはコードの記述次第ですが、それは私のストーリーの別のトピックです...感謝します!
Christian Ivicevic

9

Tiledエディター(および他のいくつかのマップエディター)で使用されるTMXマップ形式を使用できます。

Tiledを自分で使用しなくても、TMX形式は前述のすべての機能をサポートし、さまざまな言語用の既存のローダー/パーサーがいくつかあります。また、フォーマットを理解し、独自のゲームに拡張することも非常に簡単です。


TMXマップ形式に少し基づいて現在のXMLコンセプトを作成し、RapidXMLですべてのファイルを読み取ります。後で、カスタムバイナリファイル形式に移ります。
Christian Ivicevic
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.