Проектирование (текстуры) системы ресурсов
Для игры с открытым исходным кодом я хотел перестроить систему управления ресурсами, но попал в тупик и мне нужно несколько указателей на некоторые материалы для чтения или куда идти сейчас.
Начальная точка была (в основном) Loader
Заголовок класса / Src
Формат ресурсов:
- Ресурсы (как правило) находятся в архивах, которые состоят из пронумерованных файлов (без имен), которые могут быть любого типа и могут содержать связанные метаданные (размер, смещение отрисовки,...)
- Часто распространенные форматы (wav, midi, bmp), но возможны пользовательские форматы, например, для текстур:
- 2D Offset (перевод матрицы модели)
- Цветная маска игрока (дополнительная шкала серого bmp)
- Разделенные bmp (например, ссылки (индексы) на тело и голову (bmps) для повторного использования bmps в одном файле)
- Возможны расширения / перезаписи: 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,...);}