Создание упакованного двоичного представления набора файлов? - PullRequest
3 голосов
/ 13 сентября 2009

Так что я пытаюсь поработать над своей маленькой трехмерной игрой. Теперь я более или менее занимаюсь этим, чтобы выучить 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]
.
.

Сейчас я просто хочу, чтобы он хранил простые картинки и текстовые файлы. Я немного осмотрелся, и лучшее, что я действительно нашел, это старый пример того, как хранятся Doom Wad's.

У кого-нибудь есть опыт?

Ответы [ 5 ]

3 голосов
/ 13 сентября 2009

Отлично. Если вы можете загрузить все в виртуальную память и разрешить обмен, то вы можете использовать любой формат, действительно. Если вам нужен произвольный доступ только к одной записи (например, вы можете загружать их лениво, хотя несжатый memmap также ленив), то вы, вероятно, хотите сохранить индекс в памяти.

Большинство людей используют библиотеку, которая дает им доступ к .zip, .jar, .pak (формат quake) или другим аналогичным (сжатым или нет) форматам архивов, как если бы они были частью файловой системы (то есть записи доступны через строковые ключи). Я бы определенно пошел по этому пути, если бы вы могли найти уже созданную библиотеку, например, truezip для Java. У Apache Commons есть такой, но я не знаю, насколько легко интегрировать с / .NET (я полагаю, что это большая база кода на C). ZipFS выглядит так, как будто это настоящий установщик ZIP-файлов .NET, который хранит только заголовки в памяти.

Или, возможно, с чуть меньшим удобством, вы можете использовать DotNetZip напрямую

1 голос
/ 15 сентября 2009

Ваш дизайн мне нравится, хотя я предполагаю, что вы имели в виду 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". Вот как я думаю, что вы пошли бы по этому поводу:

  1. Откройте файл пакета.
  2. Читайте в заголовке фиксированного размера.
  3. Извлечение смещения индекса и количества записей из заголовка.
  4. Искать начало индекса.
  5. Считать индекс в массив (фиксированный размер записи индекса, умноженный на количество записей).
  6. Поиск по индексу для актива под названием "TankTexture.png".
  7. Извлечение смещения и размера актива из записи индекса.
  8. Искать начало актива.
  9. Считайте количество байтов, указанное размером актива.

Конечно, для последующих активов вам понадобятся только шаги 6-9.

Надеюсь, это поможет объяснить, о чем я думал. Дайте мне знать, если у вас есть другие вопросы.

1 голос
/ 13 сентября 2009

Не тратьте свое время на изобретение собственного формата хранения.

Вы можете использовать SharpZipLib или другую бесплатную библиотеку сжатия для .net. С его помощью вы также можете упаковать несколько файлов в один архив и извлекать нужные файлы отдельно по запросу.

0 голосов
/ 16 сентября 2009

Я говорю, что твой формат - хороший выбор. В идеале вы хотите использовать все свои ресурсы за одно чтение. Например, вы хотите, чтобы все ваши данные для уровня 3 в одном пакете, таким образом, вы можете загрузить все данные уровня в одном чтении без поиска. Это действительно нормально иметь один актив в более чем одном пакете. Вам просто нужно обработать случай, когда актив уже загружен, и пропустить его.

То, как вы разделяете ваши данные, должно зависеть от зависимостей между вашими данными (т. Е. Если скрипту нужна определенная модель, они оба должны быть в одном пакете) и от того, насколько гранулярным вам нужно сделать чтение (например Вы читаете все данные уровня за один раз? Тогда вы можете поместить своих врагов в пакет уровней. Но если ваша игра течет в мире, возможно, вам нужны отдельные пакеты для врагов.)

Действительно, отслеживать ваши зависимости от данных - сложная задача. Во время сборки вы хотите знать зависимости каждого фрагмента данных, которые вы извлекаете. Во время выполнения вы просто хотите прочитать в своем пакете и увидеть активы в памяти. Вам также необходимо отслеживать зависимости во время выполнения, потому что вам нужно знать, что безопасно РАЗГРУЗИТЬ в любое время.

0 голосов
/ 14 сентября 2009

Если вы хотите сделать это для целей обучения, тогда вам следует начать с формата WAD. Тем не менее, я бы предложил использовать формат фрагментированного файла.
Таким образом, он будет в основном соответствовать предложенному вами формату (т. Е. Заголовок, оглавление и т. Д.), Но для каждой записи данных у вас будет идентификатор куска, который определяет тип данных.
Это имеет много преимуществ, в основном, в том, что вы можете изменять формат данных в зависимости от формата кода, настраивая код на пропуск кусков, которые он не понимает - это позволяет продолжить разработку инструментов, сохраняя обратную совместимость ваших данных в игре.

Я бы также рекомендовал иметь в вашей оглавлении дополнительную 32-битную запись 'flags', которая позволит вам использовать битовое поле для включения таких опций, как тип сжатия, шифрование и т. Д.

Надеюсь, что поможет

...