Pull to refresh

Менеджер ресурсов.

Reading time 5 min
Views 4.4K
Сегодня я хочу рассказать об одной из составляющей современных игр, а точнее игровых движков. Её не обсуждают игроманы, о ней не пишут в рекламных проспектах и обзорах, но без неё невозможно создать современный графический движок. Эта состовляющая — менеджер ресурсов.
Менеджер ресурсов на прямую не влияет ни на качество звукового сопровождения игры, ни на её «красивость», однако без хорошего менеджера ресурсов не будет ни многообразия звукового сопровождения, ни буйности красок тяжелейших текстур.
В данной статье я попытаюсь описать несколько реалицаций менеджера. Каждая реализация подходит для проекта своего уровня, у каждой есть как плюсы, так и минусы.

Основные понятия.


Чтобы говорить о менеджере ресурсов необходимо вначале ввести определение ресурса. Менеджеры, которые я буду рассматривать имеют дело только с виртуальными возобновляемыми ресурсами. Далее я буду придерживаться такого определения:
Ресурс — это некоторый объект, доступ к которому можно можно получить по ссылке. Данный объект может быть создан, использован, удалён.

В играх ресурсы — это практически всё что мы видим и слышим (модели, текстуры, звуки и даже, иногда, код).

Реализация нулевая (отсутствие реализации)


Данная реализация состоит в том, что каждый модуль будущего игрового движка грузит и хранит все свои данные сам. При создании нового игрового объекта (при загрузке игры) идёт обращение к диску, всё что надо грузится и сохраняется где-то внутри класса игрового объекта. Данная функциональность быстро реализуется, игра грузится и работает на тестовых текстурах. Однако с появлением в наполнении игры большого количества тяжёлых текстур она начинает очень долго грузится, выгружаться и занимает огромное количество оперативной памяти. Причина кроется в том, что каждая суперкрасивая, но супертяжёлая текстурка от ваших дизайнеров грузится и хранится отдельно для каждого игрового объекта. То есть если в игре 25 одинаковых кубиков, то в памяти будет находится 25 копий карт, а при загрузке текстура будет 25 раз загружена с диска. Неплохо, правда?

Плюсы данного подхода:


Быстрая реализация на маленьких проектах.

Минусы данного подхода:


Повторная загрузка и хранение одинаковых данных.

Реализация первая (протоменеджер. Разделяемая память)


Текстура кубика не уникальна, поэтому вполне можно хранить одну её копию, а потом просто рассказывать где эта копия всем кубикам-объектам. Мы выделяем память под тексуры, грузим их в неё, а когда создаём объект, просто указываем ему где лежит его текстура. Главный плюс данного метода — это быстрота реализации. Главный минус — нерасширяемость. Для каждого нового объекта писать код, грузящий его текстуры, правильно передавать ссылки на них, следить за освобождением всех областей памяти с текстурами — очень сложно. Также так как мы не знаем время создания объекта вся загрузочная нагрузка ложится на момент загрузки игры или уровня. Также критический момент — окончание игры, когда из памяти будет выгружено огромное количество различных ресурсов.

Плюсы данного подхода:


Текстура грузится только один раз.

Минусы:


Необходимость руками прописывать где какая текстура лежит.
Большая нагрузка при загрузке и выгрузке игры (уровня).

Реализация вторая (Полный функционал)


На данном этапе можно уже выделить менеджер ресурсов как отдельный блок.
Пару слов о том как он выглядит:

1. Менеджер рабортает с абстрактным понятием «ресурс», который он может создать, дать в пользование или уничтожить. В итоге мы будем им управлять всем, что мы видим и слышим в игре. (Выполнение данного пункта необязательно, но если он будет работать только с текстурами, то это будет менеджер текстур, если моделей — моделей и т.д.).
2. Каждый ресурс имеет свой идентификатор, который однозначно определяет этот ресурс. По сути, это путь к файлу этого ресурса.
3. Работа с менеджером сводится к двум обращениям извне: хочу_получить_ресурс(идентификатор) и мне_больше_не_нужен_ресурс(идентификатор). Был ли уже загружен этот ресурс — это дело менеджера и никого это больше не касается.

Плюсы данного подхода:


Ресурс грузится только один раз и только тогда, когда нужен его первый клон.
Относительная простота реализации.
Появляется новый блок, который начинает кушать процессорные такты, но такты тратятся только при требованиях и освобождениях ресурса.

Минусы:


Данные приходится упаковывать в интерфейс ресурс.
Перед появлением первой копии тяжёлого ресурса будет задержка на загрузку (лаг). Большинство таких ресурсов получится снести в загрузку, но некоторые останутся.

Реализация третья. (Усложнённая)


Для того, чтобы при появлении нового ресурса отрисовка не задерживалась, вводится понятие «незагруженный ресурс». То есть как только поступает запрос хочу ресурс такойто, а данный ресурс не загружен, менеджер сразу отвечает указателем на память, где будет распологаться ресурс, но самого ресурса там нет, зато взведён флаг, что он незагружен. Далее есть два распостранённых варианта:
Игра продолжает играться вобще без ресурса. Такой вариант часто приемлем. Например, если у вас шутер и на горизонте (границе отрисовки) появилось здание на пару сотен тысяч поликов, то пока вы до него дойдёте и оно сможет внести какой-либо вклад в игровой процесс, оно вполне успеет загрузится.
Сначала грузится проторесурс, который очень мало весит.(Вы идёте в шутере, а вдали появляется куб с текстурой-решёткой. А пока вы подойдёте загрузится модель с окнами и текстура пористого бетона или кирпича.)
Примечание: естественно, если вы кинули гранату, а у вас нет анимации взрыва в памяти, такой подход вам не поможет.

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

Плюсы данного подхода:


Довольно незаметная подгрузка тяжёлых ресурсов.
Все плюсы обычного менеджера.

Минусы:


Приходится создавать дополнительные потоки.
Усложнение интерфейса ресурса.
Усложнение интерфейса менеджера (Необходимость создать методы: выдай ресурс немедленно).
Появление дополнительных потоков (или метода update), а в следствии — усиленного потребления тактов.

Что дальше?


Дальше можно выделить два подхода к управлению ресурсами.
1. Это контролировать все ссылки на ресурсы. Как только на ресурс никто не ссылается, то выгружать его. Ресурс забыт. Но данная технология, это уже Garbadge collector.
2.Применение стратегий к ресурсам. Допустим надо визуализировать процесс падения капель из крана: капля появляется (грузится), летит, падает в плошку (выгружается) и через секунду капля появляется вновь. Если применить стратегию выгрузки не после того как все о ресурсе забыли, а только через некоторое время, то можно здорово сэкономить такты на повторной загрузке/выгрузке. Но стратегия сильно повысит количество расходуемых тактов.

Вместо заключения.


Данная градация менеджеров была придумана мной и не претендует на абсолютную полноту и точность. Многие вопросы остались нераскрытыми, например, хранение ресурсов и методы их загрузки, но, я надеюсь, что она показывает на необходимость учитывать и разрабатывать в своих проектах не только графику/физику/озвучку, но и целый пласт обслуживающего кода.
Tags:
Hubs:
+10
Comments 2
Comments Comments 2

Articles