на каком движке сделана лига легенд
Legends of Runeterra и League of Legends: Wild Rift работают на движке Unity
Riot Games передаёт, что в основу карточной игры Legends of Runeterra и League of Legends: Wild Rift (LoL для консолей и мобильных устройств) лёг движок Unity. При создании этих игр сотрудники Unity Technologies активно консультировали разработчиков и обеспечивали техническую поддержку.
По словам девелоперов, технология позволит перенести уникальный геймплей, удобное управление и обширный мир «Лиги легенд» на ещё большее число платформ, расширив аудиторию:
Благодаря технологиям Unity мы сделаем уникальный игровой опыт League of Legends доступным наибольшему числу игроков на самых разных платформах. Мы хотим, чтобы наши пользователи могли играть там, где им удобно, и богатая функциональность Unity позволит нам достичь этой цели. При поддержке специалистов по разработке мы уже используем возможности Unity шире, чем когда-либо прежде.
Как отмечает компания, в игры по вселенной League of Legends играют миллионы человек в 150 странах мира. Но и этого мало — Riot хочет вовлечь в свои проекты миллиарды пользователей более чем на 20 платформах, которые уже поддерживает Unity.
Напомним, что Legends of Runeterra сейчас находится в стадии открытого бета-тестирования, а полноценный релиз произойдёт на PC, iOS и Android в этом году. League of Legends: Wild Rift также стартует в 2020-м на iOS и Android, а после выйдет и на неназванных консолях.
Покадровый разбор: графический движок League of Legends
Путь каждой сцены игры от тумана войны до интерфейса.
12 января старший инженер-программист Riot Games Тони Альбрехт (Tony Albrecht) рассказал в техническом блоге компании о том, как работает рендеринг в MOBA League of Legends и почему её движок требует переработки.
DTF публикует перевод статьи.
Привет, я Тони Альбрехт, один из инженеров Render Strike Team — нового начинания в League of Legends. Эта команда должна улучшить движок рендеринга игры, и нам не терпится приступить к работе. Я коротко расскажу о том, как движок работает сейчас.
Для меня это отличный повод пройтись по этапам графического конвейера для того, чтобы команда поняла, над чем нам предстоит работать. Я расскажу, как League строит и отображает отдельный кадр в игре (напомню, на мощных компьютерах это происходит более 100 раз в секунду). Обсуждение будет насыщено техническими подробностями, но я надеюсь, окажется доступным даже для тех, у кого нет опыта в рендеринге.
Для начала — пара слов о доступных нам графических библиотеках. League должна работать максимально эффективно на многих платформах. Например, Windows XP сейчас четвёртая по популярности ОС среди наших игроков (после Windows 7, 10 и 8). Каждый месяц пользователи Windows XP участвуют в более чем 10 миллионах матчей, и чтобы сохранить обратную совместимость, мы должны поддерживать DirectX 9 и использовать только его фишки. Мы пользуемся в целом аналогичным набором функций из OpenGL 1.5 на компьютера с OS X, но это скоро изменится.
В большей части компьютеров установлены CPU (центральный процессор) и GPU (графический процессор). Центральный процессор отвечает за логику и вычисления игры, в то время как графический получает от него треугольники (triangles) и текстуры и отображает их на экране как пиксели. Пиксельные шейдеры (pixel shaders) — небольшие программы на GPU, позволяющие нам влиять на то, как проходит рендеринг.
Например, можно изменить то, как текстуры накладываются на треугольники, или заставить GPU выполнить вычисления для каждого тексела текстуры. Таким образом, возможно применить текстуру к треугольнику, или наложить на него множество различных текстур, или запустить более сложные процессы, вроде бамп-маппинга (bump mapping), освещения, отражений или высокореалистичных шейдеров кожи. Все видимые объекты отрисовываются в кадровом буфере и показываются на экране, когда рендеринг завершён.
Рассмотрим пример. Вот изображение Гарена, демонстрирующее все 6 336 треугольников на каркасе — монолитная модель без текстур. Её создали наши художники и экспортировали в формат, который может читать и анимировать движок League. Можно заметить неплоское затенение: это ограничение приложения, используемого для исследования рендеринга.
Изображение модели без текстур не только скучное, но и неясное. Оно не передаёт того Гарена, которого мы все знаем. Чтобы оживить героя, нужны текстуры.
Это уже на что-то похоже. Шейдер, который рендерит наши сетки со скиннингом (skinned meshes), не только накладывает текстуры на модели, но об этом мы ещё поговорим позже.
Это основы, но League должна рендерить не только модель чемпиона и текстуры. Рассмотрим поэтапно весь рендеринг приведённой ниже сцены.
До начала отрисовывания сцены мы должны приготовить туман войны и тени (туман и тени — звучит зловеще). Центральный процессор хранит туман войны в виде сетки (grid) 128 на 128, которая масштабируется до квадратной текстуры 512 на 512. После мы размываем эту текстуру и с её помощью затемняем соответствующие зоны и области на миникарте.
Тени — обязательная часть 3D-сцены, без них будет казаться, что объекты висят в воздухе. Тени следует рендерить относительно источника света, чтобы казалось, что их отбрасывают миньоны или чемпион. Расстояние от источника света до объекта, отбрасывающего тень, учитывается для каждого пикселя в RGB-компонентах, а альфа-компонент обнуляется.
На первом изображении ниже — поле высоты теней (shadow height field) осаждённой башни, миньонов и двух чемпионов в RGB. На втором — только альфа-компонент. Текстуры были обрезаны, чтобы детали теней были виднее: миньоны внизу, а башня и чемпионы — наверху.
Наконец, мы размываем тени, сглаживая их границы (отображение которых недавно оптимизировали для повышения частоты кадров). В итоге получается текстура, которую можно наложить на статичную геометрию, чтобы создать эффект тени.
Приготовив туман войны и текстуры теней, мы начинаем отрисовывать оставшуюся часть сцены в кадре. В первую очередь это статичная геометрия (static geometry), то есть объекты без анимации. Она объединяет туман войны и информацию о тенях с собственной основной текстурой. В результате получается такое изображение:
Обратите внимание на тени миньонов, а также на туман войны, залезающий на границы сцены. На карте Ущелье призывателей (The Summoner’s Rift) для статичной геометрии не рендерятся динамические тени. Главный источник света не движется, поэтому тени статичных сеток (static meshes) «запекаются» на их текстурах. Так художники могут лучше контролировать внешний вид карты, и улучшается производительность (поскольку не нужно рендерить тени от статичных сеток). Тени могут отбрасывать только миньоны, башни и чемпионы.
На рельеф и тени уже можно накладывать объекты. В первую очередь — миньонов, чемпионов и башни, — то есть те, что должны реалистично двигаться и иметь сгибающиеся суставы (bending joints).
Каждая анимированная сетка (animated mesh) содержит скелет (каркас из иерархически выстроенных костей) и сетку треугольников (mesh of triangles), как на изображении Гарена выше. Каждая вершина связана с костями (от одной до четырёх), при движении которых вершины двигаются на манер кожи — отсюда и название «скиннинг». Наши художники создают сетки и анимации для всех объектов и экспортируют их в формат, который загружается в League в начале игры.
Все кости сетки модели Гарена продемонстрированы на изображениях выше. Слева — его кости с названиями. Справа — вершины (голубые кубы) и жёлтые линии, показывающие их привязку к костям, которые управляют их положением.
Кроме отрисовки сеток со скиннингом в кадровый буфер шейдеры сеток рендерят их отмасштабированную глубину в другой буфер, который мы используем позже для контуров. А шейдеры скиннинга выполняют расчёт эффекта Френеля (Fresnel) и излучаемого освещения, вычисляют отражения и изменяют освещение для тумана войны.
Выделение контуров по умолчанию применяется к сеткам со скиннингом и делает их очертания чётче. Это помогает отделить их от фона, особенно в зонах с низким контрастом. На первом из изображений внизу выделение контуров выключено, на втором — включено.
Контуры получаются с помощью масштабированной глубины с предыдущего этапа, к которой применяется фильтр Собеля (Sobel filter), извлекающий границы, которые мы рендерим на каждую сетку по отдельности. Если же GPU не может выполнять рендеринг на несколько объектов одновременно, применяется резервный метод с использованием стенсил-буфера.
Покадровый разбор: как работает графический движок League of Legends Статьи редакции
12 января старший инженер-программист Riot Games Тони Альбрехт (Tony Albrecht) рассказал в техническом блоге компании о том, как работает рендеринг в MOBA League of Legends и почему её движок требует переработки.
Редакция рубрики «Рынок игр» публикует перевод статьи, выполненный изданием DTF.
Привет, я Тони Альбрехт, один из инженеров Render Strike Team — нового начинания в League of Legends. Эта команда должна улучшить движок рендеринга игры, и нам не терпится приступить к работе. Я коротко расскажу о том, как движок работает сейчас.
Для меня это отличный повод пройтись по этапам графического конвейера для того, чтобы команда поняла, над чем нам предстоит работать. Я расскажу, как League of Legends строит и отображает отдельный кадр в игре (напомню, на мощных компьютерах это происходит более 100 раз в секунду). Обсуждение будет насыщено техническими подробностями, но я надеюсь, окажется доступным даже для тех, у кого нет опыта в рендеринге.
Для начала — пара слов о доступных нам графических библиотеках. League of Legends должна работать максимально эффективно на многих платформах. Например, Windows XP сейчас четвёртая по популярности ОС среди наших игроков (после Windows 7, 10 и 8). Каждый месяц пользователи Windows XP участвуют в более чем 10 миллионах матчей, и чтобы сохранить обратную совместимость, мы должны поддерживать DirectX 9 и использовать только его фишки. Мы пользуемся в целом аналогичным набором функций из OpenGL 1.5 на компьютерах с OS X, но это скоро изменится.
Рендеринг для начинающих
В большей части компьютеров установлены CPU (центральный процессор) и GPU (графический процессор). Центральный процессор отвечает за логику и вычисления игры, в то время как графический получает от него треугольники (triangles) и текстуры и отображает их на экране как пиксели. Пиксельные шейдеры (pixel shaders) — небольшие программы на GPU, позволяющие нам влиять на то, как проходит рендеринг.
Например, можно изменить то, как текстуры накладываются на треугольники, или заставить GPU выполнить вычисления для каждого тексела текстуры. Таким образом, возможно применить текстуру к треугольнику, или наложить на него множество различных текстур, или запустить более сложные процессы, вроде бамп-маппинга (bump mapping), освещения, отражений или высокореалистичных шейдеров кожи. Все видимые объекты отрисовываются в кадровом буфере и показываются на экране, когда рендеринг завершён.
Рассмотрим пример. Вот изображение Гарена, демонстрирующее все 6336 треугольников на каркасе — монолитная модель без текстур. Её создали наши художники и экспортировали в формат, который может читать и анимировать движок League of Legends. Можно заметить неплоское затенение: это ограничение приложения, используемого для исследования рендеринга.
Изображение модели без текстур не только скучное, но и неясное. Оно не передаёт того Гарена, которого мы все знаем. Чтобы оживить героя, нужны текстуры.
Текстуры Гарена лежат на диске в виде DDS- или TGA-файлов, выглядящих как кадр из фильма ужасов. Но если корректно применить их к модели, мы получим такое изображение:
Это уже на что-то похоже. Шейдер, который рендерит наши сетки со скиннингом (skinned meshes), не только накладывает текстуры на модели, но об этом мы ещё поговорим позже.
Это основы, но League of Legends должна рендерить не только модель чемпиона и текстуры. Рассмотрим поэтапно весь рендеринг приведённой ниже сцены.
Этап 0: туман войны
До начала отрисовывания сцены мы должны приготовить туман войны и тени (туман и тени — звучит зловеще). Центральный процессор хранит туман войны в виде сетки (grid) 128 на 128, которая масштабируется до квадратной текстуры 512 на 512. После мы размываем эту текстуру и с её помощью затемняем соответствующие зоны и области на миникарте.
Этап 1: тени
Тени — обязательная часть 3D-сцены, без них будет казаться, что объекты висят в воздухе. Тени следует рендерить относительно источника света, чтобы казалось, что их отбрасывают миньоны или чемпион. Расстояние от источника света до объекта, отбрасывающего тень, учитывается для каждого пикселя в RGB-компонентах, а альфа-компонент обнуляется.
На первом изображении ниже — поле высоты теней (shadow height field) осаждённой башни, миньонов и двух чемпионов в RGB. На втором — только альфа-компонент. Текстуры были обрезаны, чтобы детали теней были виднее: миньоны внизу, а башня и чемпионы — наверху.
Наконец, мы размываем тени, сглаживая их границы (отображение которых недавно оптимизировали для повышения частоты кадров). В итоге получается текстура, которую можно наложить на статичную геометрию, чтобы создать эффект тени.
Этап 2: статичная геометрия
Приготовив туман войны и текстуры теней, мы начинаем отрисовывать оставшуюся часть сцены в кадре. В первую очередь это статичная геометрия (static geometry), то есть объекты без анимации. Она объединяет туман войны и информацию о тенях с собственной основной текстурой. В результате получается такое изображение:
Обратите внимание на тени миньонов, а также на туман войны, залезающий на границы сцены. На карте Ущелье призывателей (The Summoner’s Rift) для статичной геометрии не рендерятся динамические тени. Главный источник света не движется, поэтому тени статичных сеток (static meshes) «запекаются» на их текстурах. Так художники могут лучше контролировать внешний вид карты, и улучшается производительность (поскольку не нужно рендерить тени от статичных сеток). Тени могут отбрасывать только миньоны, башни и чемпионы.
Этап 3: скиннинг
На рельеф и тени уже можно накладывать объекты. В первую очередь — миньонов, чемпионов и башни, — то есть те, что должны реалистично двигаться и иметь сгибающиеся суставы (bending joints).
Каждая анимированная сетка (animated mesh) содержит скелет (каркас из иерархически выстроенных костей) и сетку треугольников (mesh of triangles), как на изображении Гарена выше. Каждая вершина связана с костями (от одной до четырёх), при движении которых вершины двигаются на манер кожи — отсюда и название «скиннинг». Наши художники создают сетки и анимации для всех объектов и экспортируют их в формат, который загружается в League of Legends в начале игры.
Все кости сетки модели Гарена продемонстрированы на изображениях выше. Слева — его кости с названиями. Справа — вершины (голубые кубы) и жёлтые линии, показывающие их привязку к костям, которые управляют их положением.
Кроме отрисовки сеток со скиннингом в кадровый буфер шейдеры сеток рендерят их отмасштабированную глубину в другой буфер, который мы используем позже для контуров. А шейдеры скиннинга выполняют расчёт эффекта Френеля (Fresnel) и излучаемого освещения, вычисляют отражения и изменяют освещение для тумана войны.
Этап 4: контуры
Выделение контуров по умолчанию применяется к сеткам со скиннингом и делает их очертания чётче. Это помогает отделить их от фона, особенно в зонах с низким контрастом. На первом из изображений внизу выделение контуров выключено, на втором — включено.
Контуры получаются с помощью масштабированной глубины с предыдущего этапа, к которой применяется фильтр Собеля (Sobel filter), извлекающий границы, которые мы рендерим на каждую сетку по отдельности. Если же GPU не может выполнять рендеринг на несколько объектов одновременно, применяется резервный метод с использованием стенсил-буфера.
Этап 5: трава
Тени травы — часть текстуры земли, они не рендерятся динамически. Теперь добавляем траву:
Пучки травы — тоже сетки со скиннингом. Так мы можем анимировать их, когда через них проходят персонажи или при дуновении ветра в Ущелье Призывателей (Summoner’s Rift).
Этап 6: вода
После травы рендерится вода — полупрозрачные сетки со слегка анимированными текстурами волн. После добавляются кувшинки, рябь у камней и берега, насекомые. Анимация этих объектов оживляет сцену.
Чтобы подчеркнуть эффекты воды (которые не особо бросаются в глаза), я убрал геометрию под водой, но сохранил прозрачность. Это подчёркивает эффекты, чтобы нам было проще их изучить.
На следующем изображении выделен каркас всей ряби.
Здесь хорошо видны эффекты воды у берегов реки, вокруг камней и кувшинок.
Анимированная и при нормальном рендеринге вода выглядит так:
Этап 7: декали
После травы и воды добавляются декали — простые плоские элементы геометрии с текстурой, накладывающиеся на землю, вроде индикатора дальнобойности орудий башни на изображении ниже.
Этап 8: особая обводка
Некоторые контуры становятся толще при наведении мыши на объект или включении особых состояний, как у башни на рисунке ниже. Они создаются так же, как и обычные контуры, но используется более сильное размытие, чтобы сделать их толще. Также эти контуры выделяются сильнее остальных, потому что создаются на более позднем этапе рендеринга и могут перекрывать собой некоторые эффекты.
Этап 9: частицы
Далее идёт один из самых важных этапов: частицы. Я уже писал о них статью раньше. Каждое заклинание, усиление и эффект — это система частиц, которую нужно анимировать и обновлять. Конкретно эта сцена не так динамична, как, скажем, бой 5 на 5, но в ней всё равно немало частиц.
Отобразив только частицы (вообще убрав фон), мы увидим следующее:
Если показать треугольники частиц (без текстур), мы увидим фиолетовую геометрию:
А так выглядят частицы при обычной отрисовке.
Этап 10: постобработка
Теперь, когда основная часть сцены отрисована, нужно её «отполировать». Для этого мы сначала делаем проход с антиалиасингом (АА) — сглаживаем границы и делаем кадр «чище». На статичном изображении этот эффект не очень заметен, но он здорово помогает снизить эффект мерцающих пикселей, который возникает при перемещении высококонтрастных границ по экрану. В League of Legends мы используем алгоритм быстрого сглаживания Fast Approximate Anti-Aliasing.
На картинке слева — миньон без сглаживания, а справа — сглаженный с помощью FXAA. Обратите внимание, как смягчились границы.
По завершении FXAA мы осуществляем гамма-коррекцию, корректируя яркость сцены. Недавно для оптимизации экрана после гибели персонажа мы добавили в этот процесс эффект понижения насыщенности экрана. Теперь, когда чемпион умирает, не нужно заменять все видимые шейдеры сеток на обесцвеченный вариант.
Этап 11: урон и полоски здоровья
На этом этапе рендерятся игровые индикаторы: полоски здоровья, показатели нанесённого урона, и остальной экранный текст. Кроме того, отображаются не включённые в пост-обработку полноэкранные эффекты, например, эффект от урона на изображении ниже.
Этап 12: пользовательский интерфейс (HUD)
Наконец, отрисовывается пользовательский интерфейс. Текст, иконки и предметы накладываются поверх всего остального, как отдельные текстуры. В этой сцене около тысячи треугольников используются для интерфейса, около 300 для мини-карты и 700 — для всего остального.
Объединяем всё
Вся сцена содержит около 200 тысяч треугольников, около 90 тысяч из них используются только для частиц. За 625 вызовов отрисовки (draw calls) рендерится 28 миллионов пикселей. Для комфортной игры это должно происходить максимально быстро. Можно достичь более 60 кадров в секунду, если все этапы проходятся менее чем за 16,66 миллисекунд.
То, что мы описали, происходит со стороны графического процессора. Центральный процессор за это время обсчитывает всю игровую логику, обрабатывает команды ввода пользователя, коллизию, частицы, анимацию и подаёт команды на GPU. Если частота кадров у вас достигает 300, значит всё это происходит менее чем за 3,3 миллисекунды.
Зачем пересобирать движок рендеринга
Теперь вы понимаете, с какими сложностями связан рендер отдельного кадра League of Legends. Но это только со стороны вывода данных. На экране вы видите результат сотен тысяч вызовов функций к движку рендеринга — он постоянно меняется и развивается, чтобы отвечать требованиям времени. В кодовой базе игры есть разные формы рендеринга для поддержки нового и старого оборудования.
Карты работают по-разному: Ущелье призывателей (Summoner’s Rift) выполняет рендеринг немного иначе, чем Воющая бездна (Howling Abyss) или Проклятый лес (Twisted Treeline). Какие-то части движка рендеринга остались от прошлых версий League, другие — так и не раскрыли свой потенциал.
Команда Render Strike Team должна переработать код, чтобы рендеринг выполнялся через один и тот же интерфейс. Если мы с этим справимся — игроки не заметят разницы (кроме, возможно, улучшения производительности в некоторых моментах). Но после завершения работы мы сможем вносить изменения во все режимы игры одновременно.
Будущее движка Лиги Легенд
Brian «Penrif» Bossé (Tech Lead) решил поделиться мыслями об игровом движке Лиги Легенд и о том, как они принимают решения о направлении развития оного.
Существует множество направлений, в которых можно развивать движок – производительность, поддержка различных платформ, графика и т.д. В частности, в данной статье рассматривается то, как движок отражает сложность игр, реализованных на нём.
В бородатые годы в играх не было особой сложности. Они были очень просты, разрабатывались небольшими командами — часто вообще одним человеком — и за небольшой промежуток времени. По мере того, как машины становились мощнее, а ожидания игроков росли, сложность разработки также возросла. Индустрия пошла по пути, установленному Daft Punk, и ставила более сложные цели, лучшие инструменты, ускорение итераций и более…что-то там ещё. В любом случае, отрасль реагировала на эту сложность по-разному, и мало что было настолько же эффективно, как внедрение языков программирования более высокого уровня – скриптовые языки различных форм и размеров.
Где движок проводит границу между своим высокопроизводительным ядром и визуальным программирование, определяет его сложность. У вас может быть навороченный движок со сложным высокопроизводительным ядром, или же лёгкое ядро, а большая часть сложности в скриптах, ну или где-то посередине. Давайте кратко поговорим о крайностях, а затем перейдём к тому, как это относится к Лиге.
В случае с тяжёлым движком высокоуровневое программирование больше похоже на настройку, чем на, собственно, программирование. Объекты и методы, торчащие наружу, сильно абстрагированы, а их взаимодействие полностью контролируется. Если концепции движка хорошо соотносятся с потребностями игры, подобный путь подходит идеально — программисты управляют сложностью объектов и их взаимодействием, а геймдизайнеры получают песочницу с надёжными игрушками, которые легко приспособить под их прихоти. Однако если концепции не соответствуют друг другу — ждите беды.
В этом случае у вас минималистичное ядро, которое предоставляет очень простые объекты для скриптинга. Сложность использования остаётся за языком более высокого уровня, и большинство вещей в основном реализованы, если не полностью, на языке сценариев. Только критичные по производительности вещи перенесены в ядро, такие как физика и рендеринг. Сложность можно укротить с помощью программных конструкций более высокого уровня, особо не жертвуя при этом производительностью.
Определив, что оба подхода могут работать в том или ином случае, плохая новость в том, что Лига прочно обосновалась между этими двумя крайностями.
Это не самая лучшая позиция. Основное ядро предоставляет скриптовому движку как высокоуровневые конструкции, так и низкоуровневые примитивы. Язык сценариев сам по себе прост, предоставляет лишь базовые конструкции, чего и следовало ожидать от языка, работающего поверх навороченного движка, но разработчики создали сложные системы поверх него. История подобного выбора тянется далеко в прошлое, когда Брайан ещё не работал в Riot. Насколько он может судить, движок изначально был довольно легковесным, но в стремлении ускорить процесс разработки, было сделано достаточно компромиссов, вследствие чего движок уже нельзя было считать легковесным.
В нынешнем виде все части движка усложнены, и лучше бы команде выбрать один из двух стульев.
Если Лига пойдёт по этому пути, необходимо несколько важных переходов перед этим.
Во-первых, нужно сделать язык сценариев гораздо более надёжным. Продолжать с языком, заточенным под конкретную предметную область, когда вы хотите что-то сделать со сложностью процесса разработки игры в целом, немного глупо. Было бы намного лучше использовать проверенный и надёжный язык вроде C # или Python. Переход с существующего языка на один из них не составит труда — их возможности куда шире существующего языка, но этот код будет выглядеть ужасно глупо, если не использовать преимущества базовых языковых конструкций. Было бы разумно переписать значительную часть кода, чтобы кодовая база выглядела так, будто изначально писалась на новом языке.
Другой важный переход – перевод многих существующих игровых систем, в настоящее время написанных на C++, на язык более высокого уровня, оставив только высокопроизводительное ядро. Простые действия, происходящие довольно часто, останутся в ядре, в то время как функции с большей сложностью будут вынесены из него. Например, миньоны часто пересчитывают свой путь, и их довольно много. Простая логика, которая выполняется довольно часто, поэтому останется в ядре. С другой стороны, использование заклинаний чемпионами – довольно сложная штука — множество логики вокруг мгновенного каста заклинаний, во время движения или ченнелинга — там всё сложно. Происходят они не часто, так как большинство способностей имеют существенное время перезарядки, поэтому стоимость перемещения этой сложности низка.
Эти переходы позволили бы реализовать игру, над которой гораздо проще и быстрее работать – hot-reload для кода, тоже самое и для ассетов, что существенно ускорит итерации. Наличие полнофункционального языка программирования уменьшит боль в поиске «креативных» решений для выражения игрового процесса, которые не совсем соответствуют конструкциям движка. За небольшую скорость выполнения мы получили бы скорость разработки, хорошо поддерживаемую среду разработки для всех аспектов программирования и большую часть сложности, заключенную в одной экосистеме, а не разделённой. Это компромисс, на который следует пойти.
Сегодня у Лиги значительная сложность лежит именно в сценариях. Реализация очередей заклинаний, ручное управление анимациями и VFX и т.п. Логика классификации объектов часто реализуется поверх классификаций, уже присутствующих в движке — например, проверка, является ли миньон на самом деле цветком персонажа Zyra. Движение по этому пути означает перенос большей части этой сложности в движок, который, в свою очередь, предоставит богатые существительные и глаголы высокого уровня с простыми, но достаточными логическими конструкциями для их связи. Эта реализация позволила бы нетехническим специалистам овладеть всей мощью движка, не испытывая проблем со сложностью. Инженерам будет сложнее работать с движком, но всё это будет в собственном окружении вместо того, чтобы требовать от разработчиков постоянного переключения между кодом и скриптами для полного понимания реализации.
Переход к тяжеловесному движку должен привести к резкому сокращению размера и объёма сценариев. Скорее всего, сам язык сценариев сократится, и низкоуровневые конструкции будут заменены. Например, когда была добавлена конструкция для запуска события в момент захода юнита в геометрическую область, потребность в конструкции ForEachUnitInTargetArea значительно снизилась. В результате многие из этих низкоуровневых запросов и низкоуровневых действий станут излишними и должны будут удалены из производства. Они всё ещё будут использоваться при прототипировании, т.к. ожидание реализации подобных вещей в движке может затянуться.
В скриптах, по сути, останется лишь реализация уникального геймплея. Разработчики будут проводить большую часть своего времени, программируя на C ++, предоставляя новые существительные и глаголы для использования в сценариях. Это смещение фокуса позволило бы дизайнерам гораздо меньше беспокоиться о деталях реализации, сохраняя при этом их способность настраивать пользовательский опыт. Потребовалось бы немало усилий на этом пути, но оно бы того стоило.
Оба этих варианта имеют существенные преимущества по сравнению с нынешней ситуацией, так к чему стремиться? Брайан топит за легковесное ядро. Чёткое разделение на «нужна скорость» и «должно быть выразительным» очень полезно, что позволит двигать системы через эту границу, когда производительность становится более важной, чем выразительность и visa-versa.
Вернёмся к реальности. Нашим основным соображением должен быть набор навыков наших разработчиков и то, насколько хорошо они соответствуют двум альтернативам. В команде есть группа сильных сишников, некоторые из которых имеют большой опыт работы с языками более высокого уровня, но не все. Есть много не технорей (дизайнеры и художники), которые научились манипулировать текущим скриптовым решением, но полностью выпадут из цикла даже в безупречно настроенной Python среде.
Это всё ведёт к пути с навороченным движком. Можно было бы пойти по другому пути и переобучить всех для работы с легковесным движком, но это чрезвычайно дорого по времени и усилиям. Это также может привести к тому, что некоторые очень талантливые разработчики подыщут себе другое место. Поскольку оба варианта значительно лучше текущего, нет смысла плыть по течению. Команда будет стараться изо всех по направлению к тяжеловесному движку.
Движение в сторону тяжеловесного движка (и явно в противоположную от легковесного) обеспечит более надёжную опору для возрастающей сложности Лиги. Если споры такого рода вам по душе, вы C++ ниндзя и балдеете от этого языка, команда с радостью рассмотрит вашу кандидатуру.