Ремейк Overwatch в Unity
Хочу вспомнить и рассказать про свой эксперимент начала 22 года когда на закате Overwatch 1 мне захотелось изучить и воспроизвести приятную динамику движения героев чтобы лучше понять, что именно создает столь приятные ощущения управления персонажами.
Движение капсулы персонажа в OW ощущается очень отзывчивым, но в то же время обладает инерцией, что особенно хорошо заметно при высоком фреймрейте. Существует подробный доклад GDC про разработку анимаций к игре, но мне хотелось воссоздать на практике тот результат, которого они добились.
Чтобы повторить эту динамику нужно было точно подобрать параметры скорости и ускорения капсулы героя чтобы не полагаться на глаз и не упустить деталей. Для этого я воспользовался конструктором режимов overwatch workshop.
В workshop я написал скрипт, который отслеживает положение персонажей, выводит в интерфейс скорость за прошедший сетевой кадр (0.05с) и ускорение.
Оказалось, что разгон у всех персонажей почти мгновенный (0.1с, два сетевых кадра), а вот замедление и остановка происходят по-разному в зависимости от героя. Так, Soldier-76 останавливается за 0.2с, а Lucio за 0.6с (* В OW2 почти все персонажи кроме Lucio и Echo стали замедляться за 0.1с).
Скорость движения без бустов почти у всех одинаковая: 5.5м/с - 6м/с, и 90% от неё при движении назад.
Затем я обнаружил, что гравитация капулы при прыжках нестандартная, и ускорение свободного падения составляет 14мс^2 вместо земных 9.8мс^2, что создает ощущение игрушечности, но добавляет динамики прыжкам.
Чтобы убедиться в корректности динамики мне захотелось построить знакомый уровень. Поначалу я стал воссоздавать его на глаз, но потом нашёл инструмент распаковки оригинальных ресурсов игры OWLib (https://github.com/overtools/OWLib) и это вовлекло меня в многосторонний процесс переноса оригинальных ресурсов в unity.
Я выбрал тестовый уровень и заметил, что экспортированная модель очень неоптимальна и занимает несколько сотен МБ. Оказалось, это происходит потому, что модули из которых собрана сцена сохранены как отдельные объекты, а не инстансы. Чтобы это исправить, я написал скрипт Link Similar Meshes для blender который перебирает все объекты, сравнивает число вершин, материалов, и других параметров, и позволяет быстро отыскать идентичные элементы, а затем обобщить их, превратив в инстансы. Это позволило сократить объем модели уровня с 200мб до 15мб, а также задействовать инстансинг геометрии во время рендеринга и повысить фреймрейт который очень важен при оценке ощущения от управления.
UPD: обильная критика моих одноразовых скриптов для линковки подтолкнула меня доработать полноценный плагин, пользуйтесь:
Кроме оригинальных уровеней мне удалось извлечь и персонажей с анимациями. Это подтолкнуло сделать и следующий шаг: повторить контроллер анимаций. Я выбрал Солдата-76 как самого стандартного героя с привычным управлением и интересной динамикой движения в спринте.
Сначала я просто прикрепил его автомат к капсуле и попробовал подобрать положение относительно камеры. Тут же я обнаружил, что угол обзора (FOV) у камеры для первого лица отличается от FOV камеры для окружения. Более того, он изменяется во время быстрого движения героя, создавая иллюзию более стремительного бега. Путём сравнения скриншотов я подобрал нужные значения. FOV камеры для первого лица оказался равен ~58.7, а для окружения - настраивается (todo: выяснить в каком диапазоне).
В оригинальной игре движение от первого лица сопровождается очень тщательно настроенными деталями анимации которые наслаиваются друг на друга и зависят от различных факторов.
Самое важное - это процедурная анимация наведения оружия на прицел. Когд�� игрок вращает камерой, ствол оружия не прикреплен к ней намертво, а использует имитацию упругой связки чтобы передать ощущение веса оружия.
Я не нашёл готовых анимаций для этого среди извлечённых, поэтому решил воссоздать динамику такой пружины програмно. Идея оказалась нетривиальна. Оружие не просто плавно следует за целевым поворотом (что создало бы ощущение запаздывания), а наоборот - копирует угловую скорость поворота камеры и поворачивает дальше, чем нужно. И лишь при остановке плавно возвращается на место с фиксированным темпом. Я добавил ограничения для максимальных углов опережения, вывел все настройки этой динамики в параметры, и подобрал значения на глазок чтобы они соответствовали оригиналу. Ощущение от прицеливания стали гораздо лучше, появилась инерция при поворотах при сохранении отзывчивости. Но не хватало еще ощущений от движения и бега.
Почти сотню (83) анимационных клипов для персонажа от 1 лица пришлось сначала тщательно разобрать и переименовать, а затем собрать в анимационное дерево на нескольких слоях.
1 слой - базовая анимация. Там выделены состояния покоя (IDLE), движения (LOCOMOTION), перезарядки и приземления. При движении и приземлении смешиваются две анимации по параметру скорости.
2 слой - аддитивный для наклона при стрейфе. Он смешивает две анимации, создающие дополнительные повороты и покачивание оружия при движении игрока вбок.
3 слой - аддитивный слой дыхания. Солдат дышит с разным темпом в состоянии покоя и в состоянии бега, что сопровождается характерными звуками дыхания в оригинальной игре. Я не стал реализовывать систему накопления усталости и восстановления дыхания, а добавил только одну аддитивную анимацию, добавляющую медленное покачивание оружию. Но идея изменения динамики дыхания это классная изюминка оригинальной игры, показывающая внимание к деталям.
Ну и последнее что я сделал - добавил модель с анимациями для отображения персонажа от 3 лица. В анимации от 3 лица удалось создать довольно простое дерево смешивания по направлению вектора движения и смешать 8 анимаций бега. Сложнее было настроить кинематику прицеливания. Для этого пришлось воспользоваться Animation Rigging пекеджем, настроить риг, и вращать торс и голову персонажа по направлению прицела от первого лица вокруг специально подобранной точки.
Что можно еще можно было бы сделать:
1) Добавить покачивание камеры и изменение FOV. Многие анимации сопровождаются очень легким наклоном камеры, неплохо бы разобраться как это устроено у разных героев. Может быть есть боббинг камеры или шейк при каких-то событиях игры, надо изучать.
2) При приближении к препятствиям оружие сейчас проваливается в геометрию. Используя стекинг камер нужно рендерить оружие на отдельном слое. Но непонятно как быть с тенями которые попадают на оружие внутри стены. Эта проблема есть и в оригинале, но тени там как-то плавно исчезают, и проблема почти незаметна.
3) Стрельба, перезарядка, приседание, полёт, лазание по стенам. Можно воссоздать разные способы передвижения.
4) Применение абилок - рывки, телепортации, полёты, крюк-кошка и т.п.
5) Мультиплеер. В целом несложно синхронизировать стандартные движения: реплицировать вектора движения и взгляда, события. Сложнее будет сделать лагокомпенсацию и роллбэк при стрельбе проджектайлами для настоящей соревновательной игры.
6) Звуки, которые дополняют анимации движения, бега, прыжков
Ну а дальше можно воспроизвести множество специфических деталей игры чтобы сделать полноценный ремейк. Впрочем, я не ставлю перед собой этой цели. Мне хотелось бы только повторить общие принципы игрового дизайна и подготовить шаблон по которому можно было бы создавать свою игру со своим контентом и правилами, пользуясь выверенной формулой.