Brian «Penrif» Bossé (Tech Lead) решил поделиться мыслями об игровом движке Лиги Легенд и о том, как они принимают решения о направлении развития оного.
Существует множество направлений, в которых можно развивать движок – производительность, поддержка различных платформ, графика и т.д. В частности, в данной статье рассматривается то, как движок отражает сложность игр, реализованных на нём.
Типы сложности
В бородатые годы в играх не было особой сложности. Они были очень просты, разрабатывались небольшими командами — часто вообще одним человеком — и за небольшой промежуток времени. По мере того, как машины становились мощнее, а ожидания игроков росли, сложность разработки также возросла. Индустрия пошла по пути, установленному Daft Punk, и ставила более сложные цели, лучшие инструменты, ускорение итераций и более…что-то там ещё. В любом случае, отрасль реагировала на эту сложность по-разному, и мало что было настолько же эффективно, как внедрение языков программирования более высокого уровня – скриптовые языки различных форм и размеров.
Где движок проводит границу между своим высокопроизводительным ядром и визуальным программирование, определяет его сложность. У вас может быть навороченный движок со сложным высокопроизводительным ядром, или же лёгкое ядро, а большая часть сложности в скриптах, ну или где-то посередине. Давайте кратко поговорим о крайностях, а затем перейдём к тому, как это относится к Лиге.
Крайность с навороченным движком
В случае с тяжёлым движком высокоуровневое программирование больше похоже на настройку, чем на, собственно, программирование. Объекты и методы, торчащие наружу, сильно абстрагированы, а их взаимодействие полностью контролируется. Если концепции движка хорошо соотносятся с потребностями игры, подобный путь подходит идеально — программисты управляют сложностью объектов и их взаимодействием, а геймдизайнеры получают песочницу с надёжными игрушками, которые легко приспособить под их прихоти. Однако если концепции не соответствуют друг другу — ждите беды.
Крайность с легковесным движком
В этом случае у вас минималистичное ядро, которое предоставляет очень простые объекты для скриптинга. Сложность использования остаётся за языком более высокого уровня, и большинство вещей в основном реализованы, если не полностью, на языке сценариев. Только критичные по производительности вещи перенесены в ядро, такие как физика и рендеринг. Сложность можно укротить с помощью программных конструкций более высокого уровня, особо не жертвуя при этом производительностью.
А что же с Лигой?
Определив, что оба подхода могут работать в том или ином случае, плохая новость в том, что Лига прочно обосновалась между этими двумя крайностями.
Это не самая лучшая позиция. Основное ядро предоставляет скриптовому движку как высокоуровневые конструкции, так и низкоуровневые примитивы. Язык сценариев сам по себе прост, предоставляет лишь базовые конструкции, чего и следовало ожидать от языка, работающего поверх навороченного движка, но разработчики создали сложные системы поверх него. История подобного выбора тянется далеко в прошлое, когда Брайан ещё не работал в Riot. Насколько он может судить, движок изначально был довольно легковесным, но в стремлении ускорить процесс разработки, было сделано достаточно компромиссов, вследствие чего движок уже нельзя было считать легковесным.
В нынешнем виде все части движка усложнены, и лучше бы команде выбрать один из двух стульев.
Лига на пути к лёгкому движку
Если Лига пойдёт по этому пути, необходимо несколько важных переходов перед этим.
Во-первых, нужно сделать язык сценариев гораздо более надёжным. Продолжать с языком, заточенным под конкретную предметную область, когда вы хотите что-то сделать со сложностью процесса разработки игры в целом, немного глупо. Было бы намного лучше использовать проверенный и надёжный язык вроде C# или Python. Переход с существующего языка на один из них не составит труда — их возможности куда шире существующего языка, но этот код будет выглядеть ужасно глупо, если не использовать преимущества базовых языковых конструкций. Было бы разумно переписать значительную часть кода, чтобы кодовая база выглядела так, будто изначально писалась на новом языке.
Другой важный переход – перевод многих существующих игровых систем, в настоящее время написанных на C++, на язык более высокого уровня, оставив только высокопроизводительное ядро. Простые действия, происходящие довольно часто, останутся в ядре, в то время как функции с большей сложностью будут вынесены из него. Например, миньоны часто пересчитывают свой путь, и их довольно много. Простая логика, которая выполняется довольно часто, поэтому останется в ядре. С другой стороны, использование заклинаний чемпионами – довольно сложная штука — множество логики вокруг мгновенного каста заклинаний, во время движения или ченнелинга — там всё сложно. Происходят они не часто, так как большинство способностей имеют существенное время перезарядки, поэтому стоимость перемещения этой сложности низка.
Эти переходы позволили бы реализовать игру, над которой гораздо проще и быстрее работать – hot-reload для кода, тоже самое и для ассетов, что существенно ускорит итерации. Наличие полнофункционального языка программирования уменьшит боль в поиске «креативных» решений для выражения игрового процесса, которые не совсем соответствуют конструкциям движка. За небольшую скорость выполнения мы получили бы скорость разработки, хорошо поддерживаемую среду разработки для всех аспектов программирования и большую часть сложности, заключенную в одной экосистеме, а не разделённой. Это компромисс, на который следует пойти.
На пути к навороченному движку
Сегодня у Лиги значительная сложность лежит именно в сценариях. Реализация очередей заклинаний, ручное управление анимациями и VFX и т.п. Логика классификации объектов часто реализуется поверх классификаций, уже присутствующих в движке — например, проверка, является ли миньон на самом деле цветком персонажа Zyra. Движение по этому пути означает перенос большей части этой сложности в движок, который, в свою очередь, предоставит богатые существительные и глаголы высокого уровня с простыми, но достаточными логическими конструкциями для их связи. Эта реализация позволила бы нетехническим специалистам овладеть всей мощью движка, не испытывая проблем со сложностью. Инженерам будет сложнее работать с движком, но всё это будет в собственном окружении вместо того, чтобы требовать от разработчиков постоянного переключения между кодом и скриптами для полного понимания реализации.
Переход к тяжеловесному движку должен привести к резкому сокращению размера и объёма сценариев. Скорее всего, сам язык сценариев сократится, и низкоуровневые конструкции будут заменены. Например, когда была добавлена конструкция для запуска события в момент захода юнита в геометрическую область, потребность в конструкции ForEachUnitInTargetArea значительно снизилась. В результате многие из этих низкоуровневых запросов и низкоуровневых действий станут излишними и должны будут удалены из производства. Они всё ещё будут использоваться при прототипировании, т.к. ожидание реализации подобных вещей в движке может затянуться.
В скриптах, по сути, останется лишь реализация уникального геймплея. Разработчики будут проводить большую часть своего времени, программируя на C++, предоставляя новые существительные и глаголы для использования в сценариях. Это смещение фокуса позволило бы дизайнерам гораздо меньше беспокоиться о деталях реализации, сохраняя при этом их способность настраивать пользовательский опыт. Потребовалось бы немало усилий на этом пути, но оно бы того стоило.
Так какой путь в итоге?
Оба этих варианта имеют существенные преимущества по сравнению с нынешней ситуацией, так к чему стремиться? Брайан топит за легковесное ядро. Чёткое разделение на «нужна скорость» и «должно быть выразительным» очень полезно, что позволит двигать системы через эту границу, когда производительность становится более важной, чем выразительность и vice-versa.
Вернёмся к реальности. Нашим основным соображением должен быть набор навыков наших разработчиков и то, насколько хорошо они соответствуют двум альтернативам. В команде есть группа сильных сишников, некоторые из которых имеют большой опыт работы с языками более высокого уровня, но не все. Есть много не технорей (дизайнеры и художники), которые научились манипулировать текущим скриптовым решением, но полностью выпадут из цикла даже в безупречно настроенной Python среде.
Это всё ведёт к пути с навороченным движком. Можно было бы пойти по другому пути и переобучить всех для работы с легковесным движком, но это чрезвычайно дорого по времени и усилиям. Это также может привести к тому, что некоторые очень талантливые разработчики подыщут себе другое место. Поскольку оба варианта значительно лучше текущего, нет смысла плыть по течению. Команда будет стараться изо всех по направлению к тяжеловесному движку.
Что дальше?
Движение в сторону тяжеловесного движка (и явно в противоположную от легковесного) обеспечит более надёжную опору для возрастающей сложности Лиги. Если споры такого рода вам по душе, вы C++ ниндзя и балдеете от этого языка, команда с радостью рассмотрит вашу кандидатуру.