ファイルのセットのパックされたバイナリ表現を作成しますか?
質問
だから、私は自分の小さな3Dゲームで仕事をしようとしています。今、私は多かれ少なかれこれをしてC#を学びます。テクスチャ/スクリプトなどのアセットをパッケージ化するための最良の方法は何ですか?
一般的に私が考えていたことはこれでした:
[header]
[number of records]
[Offset to Record 1 from End of header]
[Offset to Record 2 from end of Record 1]
.
.
[Offset to record N from Record N-1]
[record 1]
[256 bytes represent the filename]
[32 byte size]
[binary data]
[record 2]
.
.
今は、単純な写真とテキストファイルを保存したいだけです。私はいくつかの辺りを見回しましたが、私が本当に見つけた最高のことは、運命の札束が保存される方法の古い例でした。
経験はありますか?
解決
大丈夫です。すべてを仮想メモリにロードし、スワッピングに処理させることができれば、本当にどんなフォーマットでも使用できます。 1つのレコードのみへのランダムアクセスが必要な場合(たとえば、非圧縮memmapもレイジーですが、遅延ロードが可能です)、おそらくインデックスをメモリに保持する必要があります。
ほとんどの人は、.zip、.jar、.pak(quake形式)、またはその他の類似(圧縮または非圧縮)アーカイブ形式にアクセスできるライブラリを使用します。これは、まるでファイルシステムの一部(つまり、レコードは文字列キーによってアクセスされます)。すでに作成されたライブラリを見つけることができれば、私は間違いなくそのように行きます。 Java用の truezip 。 Apache Commons には1つありますが、wの統合がどれほど簡単かはわかりません。 / .NET(これは大きなCコードベースだと思います)。 ZipFS は、ヘッダーのみを保持する実際の.NET zipファイルマウンターのように見えます。メモリ内。
または、おそらく少しだけ利便性が低い場合、 DotNetZip を直接使用できます
他のヒント
独自のストレージ形式を発明するのに時間を無駄にしないでください。
SharpZipLibまたは.net用の別の無料の圧縮ライブラリを使用できます。 また、複数のファイルを1つのアーカイブにパックし、必要に応じて必要なファイルを個別に抽出することもできます。
サイズは32 バイトではなく32 ビットを意味すると思いますが、あなたのデザインは私には良さそうです!
デザインは、シーケンシャルデザインのようなものなので、一度にすべてのアセットをロードしたい状況に最適だと思います。一度に数個のアセットのみをロードする場合(各ゲームレベルがアセットのサブセットのみを使用するため)あなたが望むこと。
その場合、よりインデックス化されたデザインを試してみるとよいでしょう。おそらく次のようなものです。
[HEADER]
[Miscellaneous header stuff]
[Offset to index from start of file]
[Number of entries in index]
[RECORD 1]
[Asset data]
[RECORD 2]
[Asset data]
.
.
[RECORD N]
[Asset data]
[INDEX]
[ID or filename of asset 1]
[Size of asset 1]
[Offset to asset 1 from start of file]
[Other asset 1 flags or whatever]
[ID or filename of asset 2]
[Size of asset 2]
[Offset to asset 2 from start of file]
[Other asset 2 flags or whatever]
.
.
これにより、ファイル全体(メモリに収まらない)ではなく、インデックス(メモリにロードする)を検索するだけでよいため、アセットのランダムアクセスが向上します。豪華にしたい場合は、インデックスにツリーまたはハッシュテーブルを使用できます。
インデックスをファイルの先頭ではなく最後に配置する理由は、全体を再構築することなく、パックファイルに別のアセットを簡単に追加できるようにするためです。そうしないと、インデックスの余分なエントリがすべてのオフセットを破棄します。
編集:コメントに返信するには...
私が念頭に置いていたのは、インデックスを介してのみアセットにアクセスすることでした。したがって、アセットを読むときにアセットの端からはみ出さないことを願っています。おそらく、典型的なユースケースの例が役立つでしょう。
" TankTexture.png"と呼ばれるテクスチャを読みたいとします。ここにあなたがそれについて行くだろうと思う方法があります:
- パックファイルを開きます。
- 固定サイズのヘッダーを読み取ります。
- ヘッダーからインデックスオフセットとエントリ数を抽出します。
- インデックスの先頭を探します。
- インデックスを配列に読み込みます(インデックスエントリのサイズを固定したエントリの数)。
- " TankTexture.png"というアセットのインデックスを検索します。
- インデックスエントリからアセットのオフセットとサイズを抽出します。
- アセットの先頭を探します。
- アセットサイズで指定されたバイト数で読み取ります。
もちろん、後続のアセットについては、手順6〜9のみが必要になります。
これが、私が考えていたことを説明するのに役立つことを願っています。他にご質問がある場合はお知らせください。
学習目的でこれを行う場合は、WAD形式を開始するのに適した場所です。ただし、チャンクファイル形式を使用することをお勧めします。
したがって、基本的には提案された形式(ヘッダー、TOCなど)に従いますが、各データエントリには、データのタイプを識別するチャンクIDがあります。
これには多くの利点があります。主に、コードを理解できないチャンクをスキップするように設定することで、コード形式に対してデータ形式を変えることができます-これにより、ゲーム内のデータの後方互換性を維持しながら、ツール開発を進めることができます。
TOCに32ビットの「フラグ」エントリを追加することをお勧めします。これにより、ビットフィールドを使用して、圧縮タイプ、暗号化などのオプションを有効にできます
役立つこと
あなたのフォーマットは良い選択だと言います。理想的には、1回の読み取りですべてのアセットをプルする必要があります。たとえば、同じパッケージにレベル3のすべてのデータが必要な場合、シークせずに1回の読み取りですべてのレベルデータをロードできます。単一のアセットを複数のパッケージに入れても大丈夫です。アセットが既に読み込まれている場合を処理し、スキップするだけです。
データの分割方法は、データ間の依存関係に依存する必要があります(つまり、スクリプトが特定のモデルを必要とする場合、両方が同じパッケージにある必要があります)。すべてのレベルデータを一度に読んだら、敵をレベルパッケージに入れることができます。
本当に、データの依存関係を追跡するのは難しい部分です。ビルド時には、プルするすべてのデータの依存関係を知りたいです。実行時には、パッケージを読み込み、アセットをメモリに表示するだけです。また、実行時に依存関係を追跡する必要もあります。これは、いつでもアンロードしても安全なものを知る必要があるためです。