Проектирование (текстуры) системы ресурсов - PullRequest
0 голосов
/ 25 августа 2018

Для игры с открытым исходным кодом я хотел перестроить систему управления ресурсами, но попал в тупик и мне нужно несколько указателей на какой-нибудь материал для чтения или куда идти.

Начальной точкой был (в основном) класс Loader Заголовок / Src

Формат ресурсов:

  • Ресурсы (обычно) в архивах, которые состоят из пронумерованных файлов (без имен), которые могут быть любого типа и могут содержать связанные метаданные (размер, смещение отрисовки, ...)
  • Часто распространенные форматы (wav, midi, bmp), но возможны нестандартные форматы, например, для текстур:
    • 2D Offset (перевод матрицы модели)
    • Цветовая маска игрока (дополнительная шкала оттенков серого)
    • Разделенные BMP (например, ссылки (индексы) на тело и голову (BMP) для повторного использования BMP в том же файле)
  • Возможны расширения / перезаписи: 2 архива с одинаковыми именами (разные папки) объединят их (более поздние загруженные записи архива добавляют или перезаписывают записи предыдущих)

Проблемы, которые я хотел решить, это грязный код (без SRP ...), неравномерная обработка ресурсов и dynamic_cast для большинства обращений (в основном: dynamic_cast<type*>(Get("foo", 42))). Наличие только одного типа текстуры также упростит рендеринг (возможно, 2: один с масками игрока, а другой без)

Мой подход (на основе ENTT):

  • ResourceLocator: с учетом имени возвращает список загружаемых архивов (обрабатывает расширение / перезаписывает)
  • ResourceCache<Type>: содержит загруженный ресурс данного типа
  • ResourceLoader<Type>: загрузка ресурса
  • ResourceRegistry: содержит несколько кэшей, 1 локатор и (возможно) загрузчики. Предоставляет доступ ко всем ресурсам, сначала проверив кеш и загрузив его по ошибке (добавив в кеш)

Это хорошо работает для звуковых эффектов и музыки:

SoundEffect& get(ResId id){
   if(id in soundcache) return it;
   archive& = get(id.name);
   SoundEffect* effect = load(archive)
   add to cache and return effect;
}

Это красиво и обобщенно. Но я борюсь за то, как это сделать для текстур, для которых у меня есть разные типы:

  • "нормальные" текстуры (фоны, кнопки ...) -> просто
  • специфичные для карты текстуры (например, деревья со снегом или без снега в зависимости от типа карты. Ранее Loader хранил ссылку на архив карт, и потребители, просто называемые GetMapTexture(idx) ->, могли не требоваться для всех карт , выгрузить их все при смене карты и перезагрузить по мере необходимости?
  • национальные текстуры (каждая нация имеет архив и / или смещение в архиве) -> Использование ("archive", number) в качестве ключа больше не работает.

Кроме того, может потребоваться объединение большого количества текстур (например, разделенных растровых изображений или тени со зданиями / людьми ...) и анимации. Это привело к наличию многоразмерных массивов фиксированного размера со многими различными индексами, значение которых содержится в классе Loader.

Так что "нормальные" текстуры просты: просто загрузите их в текстуру OGL и используйте их. Другим нужно (обычно) несколько изображений, объединенных в одну текстуру. Поэтому я не хочу помещать эти части в кеш текстуры, а только в комбинированный. Но наличие этих мульти-D-массивов также кажется недостатком дизайна. И как я буду ссылаться на них / использовать их? Как другие это делают?

Примечание. Индексы изображений, составляющих текстуру / bld ..., можно (вроде) легко вычислить из индекса нации, индекса здания, индекса кадра анимации, ...

Пример использования (из текущего / старого) кода:

drawAnimal(int type, int dir, int animationFrame){animal_cache[type][dir][animationFrame].draw(pos...);} drawCarrier(...){carrier_cache[carriedWare][dir][animationFrame][isFat].draw(pos, playerColor,...);} drawBuilding(...){building_cache[nationIdx][bldIdx].draw(pos, playerColor,...);}

...