Смена уровня и бесшовная подгрузка локации
Для начала я хочу вам напомнить, что технически, с точки зрения самого движка, смена уровня просто означает замену одной локации на другую.
Технически локация может быть оформлена как единая геометрическая модель с естественными преградами - ограничителями игровой зоны.
На момент смены локации объект игрока просто остаётся в оперативной памяти, старая модель выгружается, а новая загружается. В процессе загрузки выводится какое-либо статичное изображение. Это самый древний и наиболее распространённый механизм, который не утратил своей актуальности и сегодня. Особенно с учётом того, что большинство популярных игровых движков перебрались на 64-х битную платформу, благодаря чему получили возможность подгружать поистине гигантские уровни, на которых можно бродить часами.
Что в свою очередь делает наличие механизма бесшовной смены уровней второстепенной задачей. Это особенно актуально для одиночных игр, где каждый уровень представляет собой отдельную главу в повествовании. Пример такого подхода - Metro Exodus. Возврата на предидущие уровни
не предусмотрено, действие на каждом занимает от двух до шести часов в среднем. В данном случае у нас линейное повествование. Т.е. тип чейнджлевела в первую очередь определяется характером самой игры, а наличием технической возможности у того или иного движка. Этот момент следует учитывать.
Условно-бесшовная смена уровня, насколько мне известно, впервые появилась в игре в Half-Life, где игрок мог возвращаться в те места, где он уже побывал и видеть, что там действительно ничего не поменялось - убитые NPC по прежнему лежат на своих местах, даже лужи крови на месте. Такой механизм безусловно сложнее в реализации, но как вы понимаете, раз уж его смогли сделать еще в далёком 98-м году, ничего принципиально невозможного там не было. Основной вопрос, обычно, заключается в том, какие объекты нам непременно следует сохранить, а какими можно пренебречь. Стоимость сохранения объектов не в последнюю очередь зависит от размера данных, которые должны быть сохранены, как и важности самих объектов. Так, например, часть трупов может просто исчезать после смерти, а часть останется лежать навсегда.
Чисто визуальные эффекты, как правило не сохраняются никогда, например такие, как системы частиц - очевидно хранить положение каждой частицы
слишком расточительно и не имеет смысла даже в настоящее время.
Параллельно с ростом объема сейв-файла растёт и время, необходимое на инициализацию всех объектов в заданном состоянии, фактически инициализация происходит два раза. Первый раз - в исходное состояние, второй - в сохраненное. Универсального подхода тут нет, обычно решение о том, что сохранять, а что нет, принимаются непосредственно дизайнером уровней, либо это отражено в диздоке. Сам механизм условно-бесшовной смены уровня действует аналогично классическому, лишь с той разницей, что перед выходом с текущей локации, у нас запоминается состояние её объектов на уровне. Так же нам может потребоваться некая относительная система координат, чтобы соотнести позицию игрока на предедущем уровне с позицией на следующем. Это не слишком критично, если между уровнями может перемещаться явным образом только сам игрок, а NPC к примеру респавнятся на недостижимой для игрока позиции. Механизм переноса объектов между уровнями, в наиболее полноценном виде был реализован лишь в той же Half-Life, но насколько мне известно, в первую очередь он нелюбим дизайнерами из-за некоторой непредсказуемости. Ведь игрок может вынести с одного уровня на другой какой-то предмет, которого там быть не должно и таким образом сломать игровые скрипты. Современные игры слишком велики по объему игровых локаций и наполнению контентом, так что за всем уследить просто невозможно. Условно-бесшовная смена уровней, используется, например в S.T.A.L.K.E.R (все три части).
Бесшовная смена уровня это довольно специфичная вещь, которая может принести много боли, как в процессе разработки, так и в процессе игры.
Простое решение в лоб предполагает фоновую загрузку следующего уровня прямо во время игры, однако это не является настоящим решением проблемы и может приводить к фризам во время игрового процесса. Мне неизвестны игры, которые используют подобное решение, однако это можно считать быстрым и достаточно дешевым способом апгрейда условно-бесшовной смены уровня.
Реальный механизм бесшовной смены, как правило не предполагает концепции единого уровня, но кластеризации всего доступного игрового пространства. Здесь опять-таки всё упирается в доступную оперативную память. В принципе может использоваться и комбинированный подход, это в первую очередь характерно для 32-битных систем с ограниченным объемом памяти. Т.е. некоторая глава геймплея технически умещается на очень большой карте, которая в свою очередь разбита на кластеры, подгружающиеся по мере видимости. Насколько я знаю, так устроен мир в Mafia или GTA. Сами кластеры могут иметь внутри себя локальную систему координат, которая трансформируется в абсолютную, однако могут полагаться и на точность вещественного. В первую очередь это зависит от того, какое ограничение наступит раньше - непосредственно точность координат или же размер доступной памяти для хранения очередного уровня. Для космических симуляторов как правило используют вещественное с двойной точностью, этого хватает для симуляции расстояний солнечной системы и прилегающих галактик.
Кластерная сетка может быть вложенной, где внешние ячейки представляют собой ссылки на соседние уровни, которые в свою очередь разделены уже на физические кластеры. Это позволяет создавать законченные уровни, которые кластеризуются уже на этапе компиляции и потом вручную объединять их с соседями. С графической точки зрения каждый кластер представляет собой индивидуальный буфер геометрии в видеопамяти, которые добавляются и выгружаются циклическом образом (самый дальний от игрока имеет наибольшие шансы быть выгруженным, при условии, что он невидим). Для физики может использоваться метод вложенных иерархий, т.е. в общую сцену добавляются\удаляются её кусочки - кластеры. Большинство физических движков, так или иначе поддерживает подобную модель, иногда, впрочем с некоторыми ограничениями на кол-во кластеров. Игровые объекты могут как подгружаться одновременно с кластерами, так и быть заранее подгруженными, в первую очередь это завязано на специфику самой игры. В любом случае, если модель бесшовного мира составляется из отдельных уровней (пусть и достаточно больших), от дизайнера требуется явным образом указывать точки соприкосновения.
Ускорение загрузки уровня.
Здесь на самом деле нет никакой волшебной пилюли или хитрого алгоритма. Скорость загрузки в первую очередь зависит от пропускной способности
жесткого диска, вследствие возможности по оптимизации, в первую очередь упираются в аппаратное обеспечение. Задачи программиста в этом случае не растерять потенциально быструю возможность такой загрузки, какую может предоставить железо. Наиболее очевидный способ - линейное хранение больших объемов информации, большинство игр хранят свои ресурсы в собственных игровых форматах (или же обычных архивах), что позволяет избежать лишней дефрагментации и увеличить скорость чтения таких данных. Метод известен с незапамятных времён и естественно используется по сей день без каких-либо изменений. Второй важный момент - поиск оптимального баланса между загрузкой данных с жёсткого диска и генерацией недостающих на лету. Далеко не все данные, необходимые для уровня, имеет смысл держать в неизменном виде. Случаются ситуации, когда достаточно большой объем данных куда быстрее сгенерировать на лету, нежели пытаться его читать и перегонять в оперативную память. Это тем более актуально для многоядерных систем, когда под генерацию можно спокойно отдать одно ядро. Во всех остальных случаях следует просто избегать ненужного дублирования уже загруженной информации. Одним из подходов является, например, использование отпечатков в памяти, когда загруженная модель в дисковом формате не требует дополнительных преобразований и сразу готова к использованию. Хотя в настоящее время это не так уж и критично. Ну и наконец, если всё вышеперечисленное не дало желаемых результатов, в ход идёт последнее средство - старый добрый префетчинг.
Кэширование наиболее востребованных ресурсов начинается в момент запуска игры, из-за чего возникает неприятное ощущение, будто бы она зависла. На самом деле механизм этот двойной, поскольку префетчинг также имеется и на уровне операционной системы, но там он естественно, представлен в общем виде. Поэтому, когда вы запускаете игру и у вас на экран выводится логотип студии, а потом некоторое время ничего не происходит - это оно и есть. В этот момент грузятся все те ресурсы, которые потенциально могут понадобится как для начала новой игры, так и продолжения с чекпоинта. Ресурсы для префетчинга могут как вычисляться автоматически самим игровым движком, так и быть просто прописаннами в обычный текстовый скрипт дизайнером. Разумеется, когда вы нажимаете кнопку New Game в меню, создаётся иллюзия, будто бы уровень загрузился почти мгновенно. На самом деле большинство ресурсов было загружено заранее.
Возможно стоит рассмотреть еще один вопрос, который может возникнуть у читателей. Это связано с форками некогда популярных движков от Id Software и играх, построенных на них. Порой время загрузки таких игр превшает все мыслимые пределы терпения и вызывает вполне закономерное недоумение, почему мол, в каких-то древних движках это всё длится так долго, в то время, как в современных происходит практически мгновенно.
Чаще всего это связано с использованием несжатого формата текстур. В таких коммюьнити, почему-то обожают использовать TGA и PNG форматы,
причём последний в силу особенностей формата может иметь невероятно долгую загрузку. TGA в этом плане получше, однако он всё равно занимает
довольно много места в видеопамяти, что в свою очередь тоже растягивает процесс. Над подобными вещами как правило никто не задумывается,
поскольку подобные игры делаются ради фана и не несут потенциальной угрозы возврата денег за уже купленный продукт, т.к. распространяются
бесплатно. Второй любопытный момент заключается в вертикальной синхронизации, которая может ограничивать скорость загрузки, в тех движках над подобной мелочью никто не задумывался. Ну и наконец сетевые таймауты даже для локального игрока в Id Tech 2, Id Tech 3 способны на ровном месте растянуть процесс загрузки на долгие десятки секунд. В следующих версиях, насколько я помню, эту проблему исправили.
В принципе это всё, что я могу сказать по данной теме. Если у вас возникли какие-то вопросы, вы можете задать их в комментариях.
Chukcha
Как я помню, движок сталкера хранит информацию про уровни иначе чем в халф-лайф. А смена уровней для игрока происходит куда проще, нас просто телепортируют на точку спавна в начале локации, но вот неписи ходят по уровням как по бесшовной зоне с помощью глобального графа. И назрел вопрос, будет ли в XashNT свой формат архивов игры?
Apr 12 2021 16:53
Дядя Миша
В любом таком механизме есть глобальные данные, которые доступны на любом уровне и локальные, которые действует только на конкретном уровне. В сталкере глобальный граф, да, но "ходят" - это громко сказано. Просто перемещаются в условном пространстве. Насчёт своего формата архивов - планировал использовать .zip, не вижу причин городить свой формат.
Apr 13 2021 10:37